2

I have two UITextFields in my storyboard that are meant to take in a number that the user inputs, a minPrice and maxPrice. When I click submit in the simulator, the app crashes and I receive the following error:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[3]'
*** First throw call stack:
(
    0   CoreFoundation                      0x02a881e4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x026468e5 objc_exception_throw + 44
    2   CoreFoundation                      0x02a4e376 -[__NSPlaceholderDictionary initWithObjects:forKeys:count:] + 390
    3   CoreFoundation                      0x02a7bc29 +[NSDictionary dictionaryWithObjects:forKeys:count:] + 73
    4   Parse+Storyboard                    0x0000b5b5 -[CriteriaViewController submitButton:] + 757
    5   libobjc.A.dylib                     0x02658880 -[NSObject performSelector:withObject:withObject:] + 77
    6   UIKit                               0x013083b9 -[UIApplication sendAction:to:from:forEvent:] + 108
    7   UIKit                               0x01308345 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 61
    8   UIKit                               0x01409bd1 -[UIControl sendAction:to:forEvent:] + 66
    9   UIKit                               0x01409fc6 -[UIControl _sendActionsForEvents:withEvent:] + 577
    10  UIKit                               0x01409243 -[UIControl touchesEnded:withEvent:] + 641
    11  UIKit                               0x01347ddd -[UIWindow _sendTouchesForEvent:] + 852
    12  UIKit                               0x013489d1 -[UIWindow sendEvent:] + 1117
    13  UIKit                               0x0131a5f2 -[UIApplication sendEvent:] + 242
    14  UIKit                               0x01304353 _UIApplicationHandleEventQueue + 11455
    15  CoreFoundation                      0x02a1177f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
    16  CoreFoundation                      0x02a1110b __CFRunLoopDoSources0 + 235
    17  CoreFoundation                      0x02a2e1ae __CFRunLoopRun + 910
    18  CoreFoundation                      0x02a2d9d3 CFRunLoopRunSpecific + 467
    19  CoreFoundation                      0x02a2d7eb CFRunLoopRunInMode + 123
    20  GraphicsServices                    0x02ce55ee GSEventRunModal + 192
    21  GraphicsServices                    0x02ce542b GSEventRun + 104
    22  UIKit                               0x01306f9b UIApplicationMain + 1225
    23  Parse+Storyboard                    0x000020ed main + 141
    24  libdyld.dylib                       0x038e2701 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

CriteriaViewController.h:

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

@interface CriteriaViewController : UIViewController{

IBOutlet UISegmentedControl *Segment;
}


//@property (nonatomic) IBOutlet UITextField *itemSearch;
@property (weak, nonatomic) IBOutlet UITextField *minPrice;
@property (weak, nonatomic) IBOutlet UITextField *maxPrice;
@property (nonatomic, copy) NSNumber *chosenCategory;
@property (weak, nonatomic) NSString *itemCondition;
@property (weak, nonatomic) NSString *itemLocation;
@property (weak, nonatomic) NSString *itemSearch;

@end

CriteriaViewController.m:

    #import "CriteriaViewController.h"

@interface CriteriaViewController ()
@property (weak, nonatomic) IBOutlet UISegmentedControl *itemConditionSegment;
@property (weak, nonatomic) IBOutlet UISegmentedControl *itemLocationSegment;


@end

@implementation CriteriaViewController

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

- (void)viewDidLoad
{

    [super viewDidLoad];

    // Condition UISegment
    UISegmentedControl *conditionSegmentedControl = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:@"Only New", @"Any", nil]];
    conditionSegmentedControl.frame = CGRectMake(87, 190, 157, 30);
    conditionSegmentedControl.selectedSegmentIndex = 0;
    conditionSegmentedControl.tintColor = [UIColor blackColor];
    [conditionSegmentedControl addTarget:self action:@selector(ConditionSegmentControlAction:) forControlEvents: UIControlEventValueChanged];
    [self.view addSubview:conditionSegmentedControl];


    // Location UISegment
    UISegmentedControl *locationSegmentedControl = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:@"Fast Shipping", @"Large Selection", nil]];
    locationSegmentedControl.frame = CGRectMake(67, 275, 200, 30);
    locationSegmentedControl.selectedSegmentIndex = 0;
    locationSegmentedControl.tintColor = [UIColor blackColor];
    [locationSegmentedControl addTarget:self action:@selector(LocationSegmentControlAction:) forControlEvents: UIControlEventValueChanged];
    [self.view addSubview:locationSegmentedControl];

    // Submit button
    UIButton *submitButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; // Create Round Rect Type button.
    submitButton.frame = CGRectMake(100, 100, 100, 100); // define position and width and height for the button.
    [submitButton setTitle:@"Submit" forState:UIControlStateNormal];

    [submitButton addTarget:self action:@selector(submitButton:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:submitButton];

}

- (void)ConditionSegmentControlAction:(UISegmentedControl *)segment
{
    if(segment.selectedSegmentIndex == 0)
    {
        // set condition to new
        self.itemCondition = @"new";
    }
    else if (segment.selectedSegmentIndex == 1)
    {
        // set condition to all
        self.itemCondition = @"all";
    }
}

- (void)LocationSegmentControlAction:(UISegmentedControl *)segment
{
    if(segment.selectedSegmentIndex == 0)
    {
        // set location to us
        self.itemLocation = @"US";
    }
    else if (segment.selectedSegmentIndex == 1)
    {
        // set clocation to worldwide
        self.itemLocation = @"Worldwide";
    }
}


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


//add all the info to users respective new category object
- (IBAction)submitButton:(id)sender
{
    if (self.minPrice.text.length > 0 && self.maxPrice.text.length > 0) {

        [PFCloud callFunctionInBackground:@"userCategorySave"
                           withParameters:@{@"categoryId": self.chosenCategory,
                                              @"minPrice": self.minPrice,
                                            @"maxPrice": self.maxPrice,
                                       @"itemCondition": self.itemCondition,
                                        @"itemLocation": self.itemLocation
                                            }
                                         block:^(NSString *result, NSError *error) {

                                             if (!error) {
                                                 NSLog(@"Criteria successfully saved.");

                                                     [self performSegueWithIdentifier:@"SearchCategoryChooserToMatchCenterSegue" sender:self];

                                             }
                                         }];

    }

}


- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {



    [PFCloud callFunctionInBackground:@"addToMatchCenter"
                       withParameters:@{
//                                        @"searchTerm": self.itemSearch,
                                        @"categoryId": self.chosenCategory,
//                                        @"minPrice": self.minPrice,
//                                        @"maxPrice": self.maxPrice,
//                                        @"itemCondition": self.itemCondition,
//                                        @"itemLocation": self.itemLocation,
                                        }
                                block:^(NSString *result, NSError *error) {

                                    if (!error) {
                                        NSLog(@"'%@'", result);
                                    }
                                }];

    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.

}



@end

Cloud Code:

Parse.Cloud.define("userCategorySave", function(request, response) {


  var userCategory = Parse.Object.extend("userCategory");
  var newUserCategory = new userCategory();
      newUserCategory.set("categoryId", request.params.categoryId);
      newUserCategory.set("minPrice", request.params.minPrice);
      newUserCategory.set("maxPrice", request.params.maxPrice);
      newUserCategory.set("itemCondition", request.params.itemCondition);
      newUserCategory.set("itemLocation", request.params.itemLocation);
      newUserCategory.set("parent", Parse.User.current());

      newUserCategory.save({ 

        success: function (){
          console.log ('userCategory successfully created!');
          response.success('userCategory successfully created!');
        },

        error: function (){
          console.log('error!!!');
        response.error('Request failed');
        }

      });
});

I assume the issue is that the UITextFields are sending the numbers in a format my cloud code doesn't like. In addition to this error, I would like to set it so that only numbers are allowed when inputting a value in this field.

How can I programmatically create these two fields in a way that will send the data in a format thats compatible with the cloud code, and that only allows numbers?

Shaik Riyaz
  • 11,204
  • 7
  • 53
  • 70
Ghobs
  • 839
  • 2
  • 14
  • 32
  • 9
    Instead of assuming what the problem is, and posting loads of code and expecting people to look at it all. If you learnt how to interactively debug using Xcode then you will be able to find the exact line of code that is causing the problem and then there is no need to assume what the problem might be any longer. – Gruntcakes May 27 '14 at 19:56
  • 1
    My apologies, you're right. Where can I learn to debug this sort of error? – Ghobs May 27 '14 at 19:59
  • 4
    Basic debugging is nothing to do with the type of the error initially. XCode has the ability to step over, into, up to a line of code. Just use that ability to find out where the problem is. You keep posting question after question on SO where you've not apparently even tried to find out *where* the problem is. Once you find out *where* then *why* is usually obvious, especially when combined with *reading* the error message. – Gruntcakes May 27 '14 at 20:02
  • 1
    PlaceholderDictionary is a literal dictionary, you get a crash somewhere where you create a dictionary via literal syntax @{} and apparently one of the values is nil. Add a breakpoint to All Objective-C Exceptions and see where it crashes. – pronebird May 27 '14 at 21:49
  • The problem is that you don't know the basics of debugging in iOS. – Hot Licks May 27 '14 at 22:09
  • 1
    Lots of comments suggesting you learn iOS debugging, and none pointing to [a tutorial](https://code.tutsplus.com/tutorials/beginning-ios-development-debugging-fundamentals--mobile-4463) – this one looks okay but I hope more helpful people that took time to comment will suggest a better one. In this case, you would do well to turn on an [exception breakpoint](http://stackoverflow.com/questions/17802662/exception-breakpoint-in-xcode). – Benjohn Nov 30 '16 at 11:23
  • Incidentally – your huge dump of code turned out to be handy for me, as I wanted to check it the dictionary literal `@{…}` calls the underlying method `initWithObjects:forKeys:count:`, and it looks like it does. So thanks. – Benjohn Nov 30 '16 at 11:27

2 Answers2

10

One of your properties — it looks like itemCondition — is apparently nil. This may be because your properties are weak, so the variable is getting nulled out before you get a chance to look at it, or it may be because your selected segment isn't one of the values you're testing for and thus the variable is nnever set. I can't understand why those string properties are weak, and I strongly suspect they shouldn't be.

Chuck
  • 234,037
  • 30
  • 302
  • 389
  • Well found. Assigning a weak referenced variable with `self.itemCondition = @"all";` will never work. All memory will be released at the end of that method's scope. If he were assigning it as a weak reference to another variable then there was a chance, but not for locally assigned memory. – Putz1103 May 27 '14 at 20:14
  • 1
    Well, I'm really just elaborating on the error message. It says objects[3] is nil in a dictionary constructor in the `submitButton:` method, so I just searched for `@{` in that method and called out the fourth item. To be perfectly honest, I can't wrap my head around why a variable pointing to a constant string would be getting nulled out since they're immortal (which is why I offered the alternative theory), but the error message strongly suggests it's nil, and the weak properties really don't make much sense. – Chuck May 27 '14 at 20:31
2

If it's about NSDictionary...

NSDictionary *dic = @{@"id":ID,
                      @"condition":condition,
                      @"pageNo":[NSNumber numberWithInt:pageNo],
                      @"pageSize":[NSNumber numberWithInt:pageSize]};

this is not good. If any object is nil, there will be something wrong about it.


NSDictionary * dic = [NSDictionary dictionaryWithObjectsAndKeys:
                         ID,@"id",
                         condition,@"condition",
                         [NSNumber numberWithInt:pageNo],@"pageNo",
                         [NSNumber numberWithInt:pageSize],@"pageSize",
                         nil];

this is right.

Pang
  • 9,564
  • 146
  • 81
  • 122
Amarantin1
  • 21
  • 1