【问题标题】:iOS: NSURLSession category methods not being found at runtimeiOS:在运行时找不到 NSURLSession 类别方法
【发布时间】:2014-02-07 13:59:22
【问题描述】:

我想在 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

【问题讨论】:

    标签: ios categories nsurlsession


    【解决方案1】:

    我在使用后台 NSURLSessionUploadTasks 时得到了类似的结果,在 -URLSession:task:didCompleteWithError: 委托回调期间将其反序列化为 __NSCFURLSessionUploadTasks。

    如果我是你,我会放弃这种方法,并使用组合(即在另一个对象中将 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;
    }
    

    【讨论】:

    • 是的。我已经重写了使用作文。不过,我仍然对根本原因感到好奇。向 Apple 报告了错误。
    • 你有没有发现更多关于这个问题的信息?我有同样的问题。 Apple 对您的错误报告有何回应?如果可能的话,我希望能够使用一个类别。
    • @drekka : 你能在苹果论坛上发布错误链接吗?即使我面临类似的问题,也无法从任何地方调用任何自定义 NSURLSession 子类/类别方法,只能在 iOS7 中调用。它在 >=iOS8 中运行良好。无论如何,如果你能帮助我,请告诉我。
    【解决方案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];
    

    【讨论】:

    • 问题在于 NSURLSession 对象正在被转换为它们的核心基础对象。使用这种方法仍然无法让您与 category 方法中的 self 对象进行交互。
    • @jqyao 他已经在他的代码中提到我们不能在 NSURLSession 上创建类别所以请在 NSObject 上创建类别。
    • 这有点像 hack,但它确实有效。要访问 category 方法中的 NSURLSession 方法,请验证对象是 NSURLSession,然后创建一个将 self 类型转换为 NSURLSession 的局部变量。
    • 你可以为你的方法添加前缀,例如-(void)jq_hello
    【解决方案3】:

    我尝试与@clay-bridges 做同样的事情(即为每个任务存储一个 userInfo NSDictionary),并且在使用与背景不同的会话配置的NSURLSession 时效果很好。如果您使用带有 background 配置的NSURLSession,并且您的应用程序被终止或崩溃,则上传/下载将在后台继续,由操作系统管理。上传/下载完成后,如果我尝试检索以前存储的 userInfo NSDictionary,我什么也得不到。我的解决方案是将该自定义对象/NSDictionary 存储在 request 中,而不是任务中,使用 NSURLProtocol:+setProperty:​forKey:​inRequest:,然后使用以下方法检索信息:

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

    【讨论】:

      【解决方案4】:

      您必须导入您调用自定义方法的自定义类别

      #import "NSURLSession+test.h"
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-23
        • 1970-01-01
        • 1970-01-01
        • 2017-01-28
        • 2015-08-10
        相关资源
        最近更新 更多