2014-02-07 3 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 с фоновым, которые получают десериализованную как __NSCFURLSessionUploadTask с во время ответного вызова делегата -URLSession:task:didCompleteWithError:.

Если бы я был вами, я бы отказался от этого подхода и использовал композицию (т. Е. Сделал NSURLSession иваром в другом объекте). Если вам нужно сохранить некоторую информацию с помощью 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

Yep. Я переписал, чтобы использовать композицию уже. Тем не менее, мне все же интересно узнать о первопричине. Об ошибке сообщили Apple. – drekka

+0

Вы когда-нибудь узнавали об этом еще больше? У меня такая же проблема. Любой ответ от Apple на ваш отчет об ошибке? Я хотел бы иметь возможность использовать категорию, если это вообще возможно. – stevekohls

+0

@drekka: Не могли бы вы разместить ссылку на ошибку на форуме Apple?Даже я столкнулся с подобной проблемой и не смог вызвать какие-либо пользовательские методы подкласса/категории NSURLSession из любого места, но только в iOS7. Он отлично работает в> = 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 с фоном, и ваше приложение завершается или сбой, загрузка/загрузка продолжается в фоновом режиме, управляемом ОС. Когда загрузка/загрузка заканчивается, если я пытаюсь восстановить ранее сохраненную пользовательскую информацию NSDictionary, я ничего не получаю. Мое решение сохранить этот пользовательский объект/NSDictionary в запросе, а не задачи, используя NSURLProtocol: +setProperty:​forKey:​inRequest:, а затем, получить информацию с помощью:

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

Смежные вопросы