2014-04-27 2 views
0

J'essaye de créer une catégorie pour NSURLSession (voir le code ci-dessous). La seconde, j'essaie d'appeler le setCurrentRegion l'application se bloque. Qu'est-ce que je fais mal? Ou NSURLSession ne peut-il pas être transformé en catégorie parce qu'il utilise une instance partagée? Si tel est le cas, comment puis-je transmettre des données dans le NSURLSession afin que je puisse réessayer de traiter un CLRegion si la connexion réseau échoue?NSURLSession non retenue lors de l'utilisation d'une catégorie

fichier d'en-tête

:

#import <Foundation/Foundation.h> 
#import <CoreLocation/CoreLocation.h> 

@interface NSURLSession (LocationSession) 

@property (nonatomic, strong) CLRegion *currentRegion; 

- (void)setCurrentRegion:(CLRegion *)region; 
- (CLRegion *)currentRegion; 

@end 

fichier de mise en œuvre:

#import "NSURLSession+LocationSession.h" 

@implementation NSURLSession (LocationSession) 

- (void)setCurrentRegion:(CLRegion *)region 
{ 
    self.currentRegion = region; 
} 

- (CLRegion *)currentRegion 
{ 
    return self.currentRegion; 
} 

@end 

code appelant la catégorie

if (([self checkWifi] || [self checkWWLAN]) && [rUrl initializeRemote] && [rUrl initializeRemotePassword]) 
    { 
     NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; 
     sessionConfig.allowsCellularAccess = YES; 
     sessionConfig.timeoutIntervalForRequest = 10.0; 
     NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig]; 
     [session setCurrentRegion:region]; 
     [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; 
     [[session dataTaskWithURL:[NSURL URLWithString:[rUrl setDeviceTarget:[[gObject getSwitchID] stringValue] setServiceID:serviceName setAction:actionName setActionName:actionValue setActionValue:performAction]] 
       completionHandler:^(NSData *data, 
            NSURLResponse *response, 
            NSError *error) 
     { 
      backgroundTaskCount--; 
      NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 
      id content = [responseString JSONValue]; 
      if ([data length] > 0 && error == nil) 
      { 
       NSDictionary *statusDict = [content valueForKey:responseName]; 
       NSString *status = [statusDict valueForKey:@"OK"]; 

       if ((NSNull *)status == [NSNull null] || status == nil) 
       { 
        status = [statusDict valueForKey:@"JobID"]; 
        showNotifications = [[NSUserDefaults standardUserDefaults] boolForKey:@"notifyGeo"]; 
        if (showNotifications) 
        { 
         UILocalNotification *localNotification = [[UILocalNotification alloc] init]; 
         localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:1];; 
         NSString *message = [[NSString alloc] init]; 
         message = [@"Switch: " stringByAppendingString:status]; 
         localNotification.alertBody = message; 
         localNotification.soundName = UILocalNotificationDefaultSoundName; 
         localNotification.timeZone = [NSTimeZone defaultTimeZone]; 
         [[UIApplication sharedApplication] scheduleLocalNotification:localNotification]; 
        } 

        NSLog(@"%@", @"Job ID Value"); 
        NSLog(@"%d", [status intValue]); 
        NSLog(@"%@", @"Connection Successful"); 
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 
        if (backgroundTaskCount == 0) 
        { 
         [self endBackgroundTask]; 
        } 
       }else 
       { 
        showNotifications = [[NSUserDefaults standardUserDefaults] boolForKey:@"notifyGeo"]; 
        if (showNotifications) 
        { 
         UILocalNotification *localNotification = [[UILocalNotification alloc] init]; 
         localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:1];; 
         NSString *message = [[NSString alloc] init]; 
         message = [@"Switch: " stringByAppendingString:status]; 
         localNotification.alertBody = message; 
         localNotification.soundName = UILocalNotificationDefaultSoundName; 
         localNotification.timeZone = [NSTimeZone defaultTimeZone]; 
         [[UIApplication sharedApplication] scheduleLocalNotification:localNotification]; 
        } 

        NSLog(@"%@", @"Job ID Value"); 
        NSLog(@"%@", status); 
        NSLog(@"%@", @"Connection Successful"); 
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 
        if (backgroundTaskCount == 0) 
        { 
         [self endBackgroundTask]; 
        } 
       } 
      }else 
       if ([data length] == 0) 
       { 
        NSLog(@"%@", [error debugDescription]); 
        NSLog(@"%@", [[session currentRegion] identifier]); 
        NSLog(@"%@", [[session currentRegion] debugDescription]); 
        NSLog(@"%@", @"Retrying Connection"); 
        [locationManager startMonitoringForRegion:[session currentRegion]]; 
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 
       }else 
        if (error != nil) 
        { 
         showNotifications = [[NSUserDefaults standardUserDefaults] boolForKey:@"notifyGeo"]; 
         if (showNotifications) 
         { 
          UILocalNotification* localNotification = [[UILocalNotification alloc] init]; 
          localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:1]; 
          NSString *message = [[NSString alloc] init]; 
          NSString *status = @"Connection Failure"; 
          message = [@"Switch: " stringByAppendingString:status]; 
          localNotification.alertBody = message; 
          localNotification.soundName = UILocalNotificationDefaultSoundName; 
          localNotification.timeZone = [NSTimeZone defaultTimeZone]; 
          [[UIApplication sharedApplication] scheduleLocalNotification:localNotification]; 
         } 
         NSLog(@"%@", [error debugDescription]); 
         NSLog(@"%@", [[session currentRegion] identifier]); 
         NSLog(@"%@", [[session currentRegion] debugDescription]); 
         NSLog(@"%@", @"Retrying Connection"); 
         [locationManager startMonitoringForRegion:[session currentRegion]]; 
         [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 
        } 

     }] resume]; 
    } 
} 

journal Crash:

Exception Type: EXC_CRASH (SIGABRT) 
Exception Codes: 0x0000000000000000, 0x0000000000000000 
Triggered by Thread: 4 

Last Exception Backtrace: 
0 CoreFoundation     0x182e86f50 __exceptionPreprocess + 132 
1 libobjc.A.dylib     0x18f3901fc objc_exception_throw + 60 
2 CoreFoundation     0x182e8bc04 -[NSObject(NSObject) doesNotRecognizeSelector:] + 220 
3 CoreFoundation     0x182e89930 ___forwarding___ + 912 
4 CoreFoundation     0x182da95dc _CF_forwarding_prep_0 + 92 
5 MyAPP       0x1001c11b4 0x100084000 + 1298868 
6 MyAPP       0x1001be7c8 0x100084000 + 1288136 
7 CoreLocation     0x1833e31d4 ___lldb_unnamed_function261$$CoreLocation + 712 
8 CoreLocation     0x1833dedcc ___lldb_unnamed_function156$$CoreLocation + 76 
9 CoreLocation     0x1833d8f3c ___lldb_unnamed_function16$$CoreLocation +  96 
10 CoreFoundation     0x182e47680 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 20 
11 CoreFoundation     0x182e46838 __CFRunLoopDoBlocks + 300 
12 CoreFoundation     0x182e44c28 __CFRunLoopRun + 616 
13 CoreFoundation     0x182d85c20 CFRunLoopRunSpecific + 452 
14 GraphicsServices    0x188a6dc0c GSEventRunModal + 168 
15 UIKit       0x185eb6fdc UIApplicationMain + 1156 
16 MyAPP       0x1001f9290 0x100084000 + 1528464 
17 libdyld.dylib     0x18f983aa0 start + 4 


Thread 0: 
0 libsystem_kernel.dylib   0x000000018fa7e868 __semwait_signal_nocancel + 8 
1 libsystem_c.dylib    0x000000018f9efe5c usleep$NOCANCEL + 64 
2 libsystem_c.dylib    0x000000018fa1280c abort + 116 
3 MyAPP       0x000000010021dedc 0x100084000 + 1679068 
4 CoreFoundation     0x0000000182e872e4 __handleUncaughtException + 640 
5 libobjc.A.dylib     0x000000018f3904c4 _objc_terminate() + 112 
6 libc++abi.dylib     0x000000018ec53164 std::__terminate(void (*)()) + 12 
7 libc++abi.dylib     0x000000018ec52d38 __cxa_rethrow + 140 
8 libobjc.A.dylib     0x000000018f3903a4 objc_exception_rethrow + 40 
9 CoreFoundation     0x0000000182d85c98 CFRunLoopRunSpecific + 572 
10 GraphicsServices    0x0000000188a6dc08 GSEventRunModal + 164 
11 UIKit       0x0000000185eb6fd8 UIApplicationMain + 1152 
12 MyAPP       0x00000001001f928c 0x100084000 + 1528460 
13 libdyld.dylib     0x000000018f983a9c start + 0 

Thread 1: 
0 libsystem_kernel.dylib   0x000000018fa65aa8 kevent64 + 8 
1 libdispatch.dylib    0x000000018f969998 _dispatch_mgr_thread + 48 

Thread 2: 
0 libsystem_kernel.dylib   0x000000018fa65cf4 semaphore_timedwait_trap + 8 
1 CoreLocation     0x00000001833d8e44 ___lldb_unnamed_function15$$CoreLocation + 356 
2 CoreLocation     0x00000001833dcbd4 ___lldb_unnamed_function66$$CoreLocation + 284 
3 CoreLocation     0x000000018340c974 ___lldb_unnamed_function1194$$CoreLocation + 340 
4 libxpc.dylib     0x000000018fb1b2a8 _xpc_connection_call_event_handler + 64 
5 libxpc.dylib     0x000000018fb1902c _xpc_connection_mach_event + 2128 
6 libdispatch.dylib    0x000000018f9680a4 _dispatch_client_callout4 + 12 
7 libdispatch.dylib    0x000000018f96a854 _dispatch_mach_msg_invoke + 148 
8 libdispatch.dylib    0x000000018f96e450 _dispatch_queue_drain + 552 
9 libdispatch.dylib    0x000000018f96a250 _dispatch_mach_invoke + 104 
10 libdispatch.dylib    0x000000018f96e450 _dispatch_queue_drain + 552 
11 libdispatch.dylib    0x000000018f96a4bc _dispatch_queue_invoke + 64 
12 libdispatch.dylib    0x000000018f96e450 _dispatch_queue_drain + 552 
13 libdispatch.dylib    0x000000018f96a4bc _dispatch_queue_invoke + 64 
14 libdispatch.dylib    0x000000018f96f0f0 _dispatch_root_queue_drain + 100 
15 libdispatch.dylib    0x000000018f96f4f8 _dispatch_worker_thread2 + 72 
16 libsystem_pthread.dylib   0x000000018fafd6b8 _pthread_wqthread + 352 
17 libsystem_pthread.dylib   0x000000018fafd548 start_wqthread + 0 

Thread 3: 
0 CoreFoundation     0x0000000182d9b274 CFStringFindWithOptionsAndLocale + 4880 
1 Foundation      0x0000000183927798 -[NSString rangeOfString:options:range:locale:] + 488 
2 MyAPP       0x00000001002c5fb8 0x100084000 + 2367416 
3 MyAPP       0x00000001002c8414 0x100084000 + 2376724 
4 MyAPP       0x00000001001054f8 0x100084000 + 529656 
5 libdispatch.dylib    0x000000018f968010 _dispatch_call_block_and_release + 20 
6 libdispatch.dylib    0x000000018f967fd0 _dispatch_client_callout + 12 
7 libdispatch.dylib    0x000000018f96e4a4 _dispatch_queue_drain + 636 
8 libdispatch.dylib    0x000000018f96a4bc _dispatch_queue_invoke + 64 
9 libdispatch.dylib    0x000000018f96f0f0 _dispatch_root_queue_drain + 100 
10 libdispatch.dylib    0x000000018f96f4f8 _dispatch_worker_thread2 + 72 
11 libsystem_pthread.dylib   0x000000018fafd6b8 _pthread_wqthread + 352 
12 libsystem_pthread.dylib   0x000000018fafd548 start_wqthread + 0 

Thread 4 Crashed: 
0 libsystem_kernel.dylib   0x000000018fa7ee74 __workq_kernreturn + 8 
1 libsystem_pthread.dylib   0x000000018fafd548 start_wqthread + 0 

Thread 5 name: com.apple.NSURLConnectionLoader 
Thread 5: 
0 libsystem_kernel.dylib   0x000000018fa65ca0 mach_msg_trap + 8 
1 CoreFoundation     0x0000000182e46b70 __CFRunLoopServiceMachPort + 180 
2 CoreFoundation     0x0000000182e44d00 __CFRunLoopRun + 832 
3 CoreFoundation     0x0000000182d85c1c CFRunLoopRunSpecific + 448 
4 Foundation      0x000000018397a424 +[NSURLConnection(Loader) _resourceLoadLoop:] + 344 
5 Foundation      0x0000000183a08408 __NSThread__main__ + 996 
6 libsystem_pthread.dylib   0x000000018faffe18 _pthread_body + 164 
7 libsystem_pthread.dylib   0x000000018faffd70 _pthread_start + 136 
8 libsystem_pthread.dylib   0x000000018fafd550 thread_start + 0 

Thread 6: 
0 libsystem_kernel.dylib   0x000000018fa7ee74 __workq_kernreturn + 8 
1 libsystem_pthread.dylib   0x000000018fafd548 start_wqthread + 0 

Thread 7: 
0 libsystem_kernel.dylib   0x000000018fa7ee74 __workq_kernreturn + 8 
1 libsystem_pthread.dylib   0x000000018fafd548 start_wqthread + 0 

Thread 8 name: com.apple.CFSocket.private 
Thread 8: 
0 libsystem_kernel.dylib   0x000000018fa7e76c __select + 8 
1 libsystem_pthread.dylib   0x000000018faffe18 _pthread_body + 164 
2 libsystem_pthread.dylib   0x000000018faffd70 _pthread_start + 136 
3 libsystem_pthread.dylib   0x000000018fafd550 thread_start + 0 

code mis à jour fichier d'en-tête

#import <Foundation/Foundation.h> 
#import <CoreLocation/CoreLocation.h> 
#import <objc/runtime.h> 

@interface NSURLSession (LocationSession) 

@property (nonatomic, retain) CLRegion *currentRegion; 

@end 

Fichier de mise en œuvre

#import "NSURLSession+LocationSession.h" 

static CLRegion *currentRegions; 

@implementation NSURLSession (LocationSession) 

- (void)setCurrentRegion:(CLRegion *)region 
{ 
    objc_setAssociatedObject(self, &currentRegions, region, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
} 

- (CLRegion *)currentRegion 
{ 
    return objc_getAssociatedObject(self, &currentRegions); 
} 

@end 
+0

Quel est le message de l'accident? –

+0

Crash ajouté au message original – Jarod

Répondre

4

Le compilateur traduit

self.currentRegion = region; 

dans

[self setCurrentRegion:region]; 

ce qui signifie que vous avez une récursion infinie dans votre méthode setter

- (void)setCurrentRegion:(CLRegion *)region 
{ 
    self.currentRegion = region; 
} 

Et le même problème se produit dans votre getter:

- (CLRegion *)currentRegion 
{ 
    return self.currentRegion; 
} 

Le programme se bloque alors en raison d'un débordement de pile.

Mais le problème sous-jacent est que vous ne pouvez pas ajouter une variable d'instance à une classe dans une méthode de catégorie. La seule solution pour ce problème que je sais si est d'utiliser soi-disant "objets associés" pour contenir le contenu de la propriété. Voir Objective-C Category and new iVar pour un exemple.


Mise à jour: Il y a des problèmes qui sont propres à la classe NSURLSession. Cela semble être un groupe, mais tout à fait exceptionnellement l'objet concret classe retourné par la méthode de fabrication est pas une sous-classe de NSURLSession:

NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; 
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig]; 
BOOL b = [session isKindOfClass:[NSURLSession class]]; 
// --> NO !!! 

Ceci est la raison pour laquelle le message d'exception

-[__NSCFURLSession setCurrentRegion:]: unrecognized selector sent to instance ... 

Une solution de contournement consiste à ajouter la propriété dans une catégorie à NSObject.

Mais comme il est apparu dans la discussion, la propriété était censé contenir une référence à un objet (le region) de sorte qu'il serait disponible dans le bloc d'achèvement de la méthode dataTaskWithURL:completionHandler:.

Mais ce n'est pas nécessaire (si je comprends bien le problème correctement), parce que la création d'un bloc capture les valeurs des variables qui sont référencées à l'intérieur du bloc:

CLRegion *region = ...; 
[[session dataTaskWithURL:[NSURL URLWithString:[rUrl setDeviceTarget:[[gObject getSwitchID] stringValue] setServiceID:serviceName setAction:actionName setActionName:actionValue setActionValue:performAction]] 
       completionHandler:^(NSData *data, 
            NSURLResponse *response, 
            NSError *error) 
     { 
      // ... 
      NSLog(@"%@", [region identifier]); 
      // ... 
+0

Pouvez-vous ajouter un exemple de comment ajouter un objet associé pour contenir le contenu de la propriété? – Jarod

+0

J'essaie de comprendre ce que vous entendez par un soi-disant "objets associés", mais je n'arrive pas à trouver d'exemples. Pouvez-vous s'il vous plaît poster un exemple? – Jarod

+0

@Jodod: Donnez-moi quelques minutes. Je cherche un exemple pour vous ... –