Search code examples
objective-cxcodewatchkit

WatchKit crash on sendResponse


My app is crashing and I can't track down the bug.

Its telling me on the crash:

Assertion failure in -[UIWatchKitExtensionRequestAction sendResponse:], /SourceCache/BaseBoard/BaseBoard-98.3/BaseBoard/BSAction.m:221

 **Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'this request has been neutered - you can't call -sendResponse: twice nor after encoding it'**

 **First throw call stack:
(0x1823342d8 0x193b580e4 0x182334198 0x1831e8ed4 0x188812ab4 0x10003cf94 0x10004708c 0x188812a08 0x18745dab4 0x18871f778 0x10003cfd4 0x10003cf94 0x10004ab54 0x10004c248 0x19438922c 0x194388ef0)
libc++abi.dylib: terminating with uncaught exception of type NSException**

I tried putting an exception breakpoint in, and still can't track it down. Any ideas?

Thanks!

EDIT:

AppDelegate.m:

- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *))reply {
    if (userInfo[@"pfquery_request"]) {
        NSLog(@"Starting PFQuery"); // won't print out to console since you're running the watch extension

        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
        [formatter setDateStyle:NSDateFormatterMediumStyle];
        NSString *dateToday = [formatter stringFromDate:[NSDate date]];
        NSString *dateTodayShort = [dateToday substringToIndex:[dateToday length] -6];

        // Get JSON file path
        NSString *JSONFilePath = [[NSBundle mainBundle] pathForResource:@"Days" ofType:@"json"];
        NSData *JSONData = [NSData dataWithContentsOfFile:JSONFilePath];
        NSDictionary *JSONDictionary = [NSJSONSerialization JSONObjectWithData:JSONData options:kNilOptions error:nil];
        NSArray *days;
        days = JSONDictionary[@"days"];

        // Iterate thru JSON to find Data for Today
        NSObject *todayJson;
        for (NSObject *object in days) {
            NSString *dateObject = [object valueForKey:@"day"];
            if ([dateObject isEqualToString:dateTodayShort]) {
                todayJson = object;
                NSString *textToday = [todayJson valueForKey:@"text"];

                // App Group
                NSString *container = @"group.com.rr.mm";
                NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:container];
                [defaults setValue:textToday forKey:@"textSaved"];
            }
        }
        reply(@{@"success": @(YES)});
    }
    reply(@{@"success": @(NO)});
}

I request the data in both my WatchKit InterfaceController.m and my WatchKit GlanceController.m with the same thing:

- (void)willActivate {
    // This method is called when watch view controller is about to be visible to user
    [super willActivate];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
        [WKInterfaceController
         openParentApplication:@{@"pfquery_request": @"dumm_val"}
         reply:^(NSDictionary *replyInfo, NSError *error) {
             NSLog(@"User Info: %@", replyInfo);
             NSLog(@"Error: %@", error);

             if ([replyInfo[@"success"] boolValue]) {

                 // Get Saved data
                 NSString *container = @"group.com.rr.mm";
                 NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:container];
                 NSString *text = [defaults valueForKey:@"textSaved"];

                 // Set Saved Data to Global String
                 textGlobal = text;

                 // Set text Label
                 self.textVerseLabelWatch.text = text;
             }
         }];
    });
}

Solution

  • Assuming that userInfo[@"pfquery_request"] exists, the if statement will pass and the code will run inside the if statement, including reply(@{@"success": @(YES)});. Immediately after, regardless of if the if statement passes or not, it will run reply(@{@"success": @(NO)});. This is why its called twice.

    Use the following instead.

    - (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *))reply {
        if (userInfo[@"pfquery_request"]) {
            NSLog(@"Starting PFQuery"); // won't print out to console since you're running the watch extension
    
            NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
            [formatter setDateStyle:NSDateFormatterMediumStyle];
            NSString *dateToday = [formatter stringFromDate:[NSDate date]];
            NSString *dateTodayShort = [dateToday substringToIndex:[dateToday length] -6];
    
            // Get JSON file path
            NSString *JSONFilePath = [[NSBundle mainBundle] pathForResource:@"Days" ofType:@"json"];
            NSData *JSONData = [NSData dataWithContentsOfFile:JSONFilePath];
            NSDictionary *JSONDictionary = [NSJSONSerialization JSONObjectWithData:JSONData options:kNilOptions error:nil];
            NSArray *days;
            days = JSONDictionary[@"days"];
    
            // Iterate thru JSON to find Data for Today
            NSObject *todayJson;
            for (NSObject *object in days) {
                NSString *dateObject = [object valueForKey:@"day"];
                if ([dateObject isEqualToString:dateTodayShort]) {
                    todayJson = object;
                    NSString *textToday = [todayJson valueForKey:@"text"];
    
                    // App Group
                    NSString *container = @"group.com.rr.mm";
                    NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:container];
                    [defaults setValue:textToday forKey:@"textSaved"];
                }
            }
            reply(@{@"success": @(YES)});
        } else {
            reply(@{@"success": @(NO)});
        }
    }