-1

I'm trying to have two buttons in my SearchCategoryChooserViewcontroller to display titles based on values being returned by a function. However, the buttons seem to be showing up with "null" for a title, even though the topCategoriesArray is successfully being returned. Here's my setup:

SearchCategoryChooserViewController.m:

#import "SearchCategoryChooserViewController.h"
#import "SearchViewController.h"

@interface SearchCategoryChooserViewController ()

@end

@implementation SearchCategoryChooserViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];




    UIButton *category1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    category1.frame = CGRectMake(10, 120, 300, 35);
    [category1 setTitle: [NSString stringWithFormat:@"%@", self.topCategory1] forState:UIControlStateNormal];
    [category1 addTarget:self action:@selector(myButtonClick:)    forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview: category1];


    UIButton *category2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    category2.frame = CGRectMake(10, 180, 300, 35);
    [category2 setTitle: [NSString stringWithFormat:@"%@", self.topCategory2] forState:UIControlStateNormal];
    [category2 addTarget:self action:@selector(myButtonClick:)    forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview: category2];


    // Do any additional setup after loading the view.
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end

SearchCategoryChooserViewController.h:

#import <UIKit/UIKit.h>
#import "SearchViewController.h"

@interface SearchCategoryChooserViewController : SearchViewController

@end

SearchViewController.h:

#import <UIKit/UIKit.h>
#import <Parse/Parse.h>
#import <Parse/PFCloud.h>
#import "CriteriaViewController.h"



    @interface SearchViewController : UIViewController

    @property (weak, nonatomic) IBOutlet UIButton *nextButtonOutlet;
    @property (weak, nonatomic) NSString *topCategory1;
    @property (weak, nonatomic) NSString *topCategory2;

    @end

SearchViewController.m:

#import "SearchViewController.h"

@interface SearchViewController ()

@property (weak, nonatomic) IBOutlet UITextField *itemSearch;
@property (weak, nonatomic) IBOutlet UIButton *nextButton;

@end

@implementation SearchViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.nextButtonOutlet addTarget:self action:@selector(nextButton:) forControlEvents:UIControlEventTouchUpInside];
    // Do any additional setup after loading the view.
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}




- (IBAction)nextButton:(id)sender
{
    if (self.itemSearch.text.length > 0) {
        [PFCloud callFunctionInBackground:@"eBayCategorySearch"
                           withParameters:@{@"item": self.itemSearch.text}
                                    block:^(NSDictionary *result, NSError *error) {
                                        NSLog(@"'%@'", result);


                                            NSArray *resultArray = [result objectForKey:@"results"];


                                                NSDictionary *dictionary0 = [resultArray objectAtIndex:0];
                                                NSNumber *numberOfTopCategories = [dictionary0 objectForKey:@"Number of top categories"];

                                                NSDictionary *dictionary1 = [resultArray objectAtIndex:1];
                                                NSNumber *topCategories = [dictionary1 objectForKey:@"Top categories"];

                                                NSDictionary *dictionary2 = [resultArray objectAtIndex:2];
                                                NSNumber *numberOfMatches = [dictionary2 objectForKey:@"Number of matches"];

                                                NSDictionary *dictionary3 = [resultArray objectAtIndex:3];
                                                NSNumber *userCategoriesThatMatchSearch = [dictionary3 objectForKey:@"User categories that match search"];

                                            NSArray *topCategoriesArray = [dictionary1 objectForKey:@"Top categories"];
                                                NSString *topCategory1 = [topCategoriesArray objectAtIndex:0];
                                                NSString *topCategory2 = [topCategoriesArray objectAtIndex:1];


                                        if (!error) {


                                            // if 1 match found clear categoryResults and top2 array
                                            if ([numberOfMatches intValue] == 1 ){
                                                [self performSegueWithIdentifier:@"ShowMatchCenterSegue" sender:self];
                                            }

                                            // if 2 matches found
                                            else if ([numberOfMatches intValue] == 2){
                                                [self performSegueWithIdentifier:@"ShowUserCategoryChooserSegue" sender:self];
                                                //default to selected categories criteria  -> send to matchcenter -> clear categoryResults and top2 array
                                            }

                                            // if no matches found, and 1 top category is returned
                                            else if ([numberOfMatches intValue] == 0 && [numberOfTopCategories intValue] == 1) {
                                                [self performSegueWithIdentifier:@"ShowCriteriaSegue" sender:self];
                                            }
                                            // if no matches are found, and 2 top categories are returned
                                            else if ([numberOfMatches intValue] == 0 && [numberOfTopCategories intValue] == 2) {
                                                [self performSegueWithIdentifier:@"ShowSearchCategoryChooserSegue" sender:self];
                                            }

                                        }
                                    }];
    }
}






#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
//    if([segue.identifier isEqualToString:@"ShowSearchCategoryChooserSegue"]){
//        SearchCategoryChooserViewController *controller = (SearchCategoryChooserViewController *) segue.destinationViewController;
//        controller.itemSearch.text = self.itemSearch.text;
//        }


}






@end
Ghobs
  • 839
  • 2
  • 14
  • 32

2 Answers2

3

There are multiple issues:

You should change the code:

@property (weak, nonatomic) NSString *topCategory1;
@property (weak, nonatomic) NSString *topCategory2;

to

@property (strong, nonatomic, copy) NSString *topCategory1;
@property (strong, nonatomic, copy) NSString *topCategory2;

or

//because strong is default
@property (nonatomic, copy) NSString *topCategory1;
@property (nonatomic, copy) NSString *topCategory2;

It is better if you add the ´copy´ attribute for the NSString properties in case of using NSMutableString value.

Because with ARC if there is not at least one strong reference for an object it will be deallocated. If your Object have only a weak reference to an another object, it is not own it and it will be deallocated even if you use it in your Object. But with strong reference your Object own the another Object and it will not be deallocated until your Object lives.

And you should be set the property values before perform a segue with change this code

NSString *topCategory1 = [topCategoriesArray objectAtIndex:0];
NSString *topCategory2 = [topCategoriesArray objectAtIndex:1];

to

self.topCategory1 = [topCategoriesArray objectAtIndex:0];
self.topCategory2 = [topCategoriesArray objectAtIndex:1];

and use the values in prepareForSegue:

if([segue.identifier isEqualToString:@"ShowSearchCategoryChooserSegue"]){
    SearchCategoryChooserViewController *controller = (SearchCategoryChooserViewController *) segue.destinationViewController;
    controller.itemSearch.text = self.itemSearch.text;
    controller.topCategory1 = self.topCategory1;
    controller.topCategory2 = self.topCategory1;
}
Roland Kákonyi
  • 583
  • 4
  • 12
  • 2
    You should really declare them as `copy` in case a mutable string is assigned to the property instead. See [this answer](http://stackoverflow.com/a/11249723/849645) for more info. Do _not_ declare them as just `nonatomic` as this uses the default of `assign`. – Rich May 05 '14 at 19:49
  • This all makes sense, however the if statement in `prepareForSegue` gives me the error `use of undeclared identifier SearchCategoryChooserViewController`. Where should I be declaring that identifier? – Ghobs May 06 '14 at 17:34
  • Check Apple's [documentation](https://developer.apple.com/library/ios/recipes/xcode_help-interface_builder/articles-storyboard/StoryboardSegue.html). You have to click on the segue and set the _Identifier_ property like [here](https://developer.apple.com/library/ios/recipes/xcode_help-interface_builder/art/interface_builder_adding_seque_3_2x.png) with the _NextScreen_ ID – Roland Kákonyi May 06 '14 at 17:58
  • My segue already had the correct identifier set, it seems the error here is referring to this part: `SearchCategoryChooserViewController *controller = (SearchCategoryChooserViewController *) segue.destinationViewController;`. – Ghobs May 06 '14 at 19:01
  • The destination controller is embedded in a navigation controller, if that helps. – Ghobs May 06 '14 at 19:10
  • Nevermind, turns out I forgot to import the header file. – Ghobs May 06 '14 at 19:14
0

It appears to me (from the code you've pasted into your question) that you are never setting your "topCategory1" string property in your SearchCategoryChooserViewController object.

Which would explain why you are seeing "null" in the label.

Michael Dautermann
  • 88,797
  • 17
  • 166
  • 215