2014-02-07 29 views
12

我想在NSURLSession上创建一个类别。该应用程序编译好了,但是当我试图调用类的方法,我得到iOS:在运行时未找到NSURLSession类别方法

-[__NSCFURLSession doSomething]: unrecognized selector sent to instance 0xbf6b0f0 
<unknown>:0: error: -[NSURLSession_UPnPTests testCategory] : -[__NSCFURLSession doSomething]: unrecognized selector sent to instance 0xbf6b0f0 

很奇怪,这里是一个测试类我建立了以显示问题。 NSString上的类别工作正常,但NSURLSession上的类别未能在运行时找到该方法。我怀疑这是内在的东西。

意见请:-)

#import <XCTest/XCTest.h> 

@interface NSString (test) 
-(void) doSomethingHere; 
@end 

@implementation NSString (test) 
-(void) doSomethingHere { 
    NSLog(@"Hello string"); 
} 
@end 

@interface NSURLSession (test) 
-(void) doSomething; 
@end 

@implementation NSURLSession (test) 
-(void) doSomething { 
    NSLog(@"Hello!!!!"); 
} 
@end 

@interface NSURLSession_UPnPTests : XCTestCase 
@end 

@implementation NSURLSession_UPnPTests 
-(void) testCategory { 
    [@"abc" doSomethingHere]; 
    NSURLSession *session = [NSURLSession sharedSession]; 
    [session doSomething]; 
} 
@end 

回答

6

我有类似的结果与中背景NSURLSessionUploadTask s,这反序列化时,你必须导入自定义类别作为__NSCFURLSessionUploadTask s在-URLSession:task:didCompleteWithError:委托回调期间。

如果我是你,我会放弃这种做法,并使用组合(即使NSURLSession在另一个对象中成为一个ivar)。如果您需要使用NSURLSession存储一些信息,则可以将一个JSON编码的字典填入.sessionDescription

下面是我用来做为任务代码:

#pragma mark - Storing an NSDictionary in NSURLSessionTask.description 

// This lets us attach some arbitrary information to a NSURLSessionTask by JSON-encoding 
// an NSDictionary, and storing it in the .description field. 
// 
// Attempts at creating subclasses or categories on NSURLSessionTask have not worked out, 
// because the –URLSession:task:didCompleteWithError: callback passes an 
// __NSCFURLSessionUploadTask as the task argument. This is the best solution I could 
// come up with to store arbitray info with a task. 

- (void)storeDictionary:(NSDictionary *)dict inDescriptionOfTask:(NSURLSessionTask *)task 
{ 
    NSData *data = [NSJSONSerialization dataWithJSONObject:dict options:0 error:nil]; 
    NSString *stringRepresentation = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 
    [task setTaskDescription:stringRepresentation]; 
    [stringRepresentation release]; 
} 

- (NSDictionary *)retrieveDictionaryFromDescriptionOfTask:(NSURLSessionTask *)task 
{ 
    NSString *desc = [task taskDescription]; 
    if (![desc length]) { 
     DDLogError(@"No description for %@", task); 
     return nil; 
    } 
    NSData *data = [desc dataUsingEncoding:NSUTF8StringEncoding]; 
    NSDictionary *dict = (data ? (id)[NSJSONSerialization JSONObjectWithData:data options:0 error:nil] : nil); 
    if (!dict) { 
     DDLogError(@"Could not parse dictionary from task %@, description\n%@", task, desc); 
    } 
    return dict; 
} 
+1

没错。我已经重新编写了使用组合。尽管如此,我仍然对好奇心很好奇。 Bug报告给苹果公司。 – drekka

+0

你有没有在这个问题上找到更多的东西?我有同样的问题。苹果对你的错误报告有何回应?如果可能的话,我希望能够使用一个类别。 – stevekohls

+0

@drekka:你可以在苹果论坛上发布bug链接吗?即使我面临类似的问题,也无法从iOS7中调用任何自定义的NSURLSession子类/类别方法。它在> = iOS8中工作正常。无论如何,请让我知道你是否可以帮助我。 –

-3

,你调用自定义方法

#import "NSURLSession+test.h" 
2

这里是一个替代的解决方案,如果你真的想类别添加到NSURLSession。我从BETURLSession找到了这个解决方案。当然,您必须非常小心名称以避免名称冲突。

代码头

#import <Foundation/Foundation.h> 

@interface NSURLSession (YTelemetry) 

-(void) hello; 
@end 

代码执行

#import "NSURLSession+YTelemetry.h" 

@implementation NSObject (YTelemetry) 

-(void) hello 
{ 
    NSLog(@"hello world"); 

} 
@end 

现在在代码中,我可以

NSURLSession *session = [NSURLSession sharedSession]; 

[session hello]; 
+1

问题是NSURLSession对象正在转换为它们的Core Foundation对应物。使用这种方法仍然不会让您与类别方法内的自我对象进行交互。 – mph

+0

@jqyao他已经在他的代码中提到我们不能在NSURLSession上做类别所以请在NSObject上做类别。 –

+0

这是一个相当有点破解,但它确实有效。要访问类别方法内的NSURLSession方法,请验证该对象是否为NSURLSession,然后创建一个局部变量,该变量将自我转换为NSURLSession。 – SwampThingTom

0

我试图做的一样@泥桥(即为每个任务存储用户信息NSDictionary),并且在将会话与NSURLSession一起使用时效果很好配置与背景不同。如果您使用NSURLSession背景配置,并且您的应用程序被终止或崩溃,则上传/下载将在后台继续,由OS管理。当上传/下载完成时,如果我尝试检索先前存储的userInfo NSDictionary,我什么也没得到。我的解决方案是该自定义对象/ NSDictionary存储在要求,没有任务,使用NSURLProtocol+setProperty:​forKey:​inRequest:,后来,检索使用的信息:

id customObject = [NSURLProtocol propertyForKey:@"yourkey" inRequest:sessionTask.originalRequest];