ios - NSURLSession 和代表

标签 ios cocoa nsurlsession

在一个小型 iOS 应用程序中,我需要从服务器检索一些 JSON(类似于 DNS 请求),并使用此响应来发起进一步的连接。为此,我有一个使用 NSURLSession 处理 JSON 请求的对象。该对象接收主对象 (MainController) 作为委托(delegate),并在 JSON 数据可用时调用方法。这是 MainController 中的调用:

- (void)serverResolve:(NSString *)serverID withPass:(NSString *)pass {
    // Must retrieve the server list from JSON
    ServerListRetriever *slCom = [[ServerListRetriever alloc] init];
    slCom.delegate = self;
    [slCom searchServer:serverID usingPass:pass];
}

我的问题是,一旦completionHandler开始运行,MainController就不会做它应该做的事情。我不知道为什么???

这是 ServerListRetriever 的内容( header ):

#import "ServerListRetrieverDelegate.h"

@interface ServerListRetriever : NSObject
@property (assign, nonatomic) id <ServerListRetrieverDelegate> delegate;

- (void)searchServer:(NSString *)serverID usingPass:(NSString *)pass;
@end

...(和实现)

#import "ServerListRetriever.h"
#define SERVER_LIST @"https://www.example.com/hosts.json"
@implementation ServerListRetriever

- (void)searchServer:(NSString *)serverID usingPass:(NSString *)pass
{
    // This will work...
    [self.delegate serverConnect:@"https://www.example.net/" withPass:pass];
    return;

    // And if removing the above two lines, this won't work
    NSURLSession *session = [NSURLSession sharedSession];
    [[session dataTaskWithURL:[NSURL URLWithString:SERVER_LIST]
            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                // Handle response
                if (error) {
                    [self.delegate serverListFailedWithError:error];
                } else {
                    // NSLog(@"Retrieved JSON: %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);

                    // Extract the server URL
                    NSError *jsonError = nil;
                    NSDictionary *parsedObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];

                    if (jsonError) {
                        [self.delegate serverListFailedWithError:jsonError];
                        return;
                    }

                    NSString *serverURL = [parsedObject objectForKey:serverID];
                    NSLog(@"Resolved server URL: %@", serverURL);

                    // Continue with connection
                    [self.delegate serverConnect:serverURL withPass:pass];
                }
            }] resume];
}

@end

方法serverConnect在这两种情况下都会运行,但是当由completionHandler调用时,很多想法将无法正常工作。我已经通过调试检查了委托(delegate),并且在这两种情况下它具有相同的 ID。

由于我仍在 iOS 上的内存管理方面苦苦挣扎,过早丢失一些对象可能是一个解释。然而,我缺乏定位问题的经验。感谢您的想法和建议!

最佳答案

关于代表是否应该强大一直存在争论。如果它们很弱,那么您保证不会出现保留循环,但这也意味着如果委托(delegate)没有被其他人保留,它可能会在异步操作完成之前消失。

通常处理这种情况的方法是制作委托(delegate)的强大内部副本,例如

@interface ServerListRetriever ()
@property (strong, nonatomic) id <ServerListRetrieverDelegate> strongDelegate;
@end

...

// When an operation is started:
self.strongDelegate = self.delegate;

// When the *last* operation ends (keep an array of operations or something):
self.strongDelegate = nil;

或者,您可以将公共(public)委托(delegate)属性标记为强,但您需要在使用完毕后显式将 ServerListRetriever 的委托(delegate)清空,或者将最后一个引用清空ServerListRetriever 对象本身。

关于ios - NSURLSession 和代表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43798152/

相关文章:

c# - EKEventStore 访问请求在 iOS 10 上崩溃

objective-c - NSFetchedResultsController,后台线程中的多线程和删除

ios - H27-客户请求中断

ios - NSURLSession 下载任务在成功后失败

objective-c - 一般的NSPasteboard能占用多少内存?

ios - 如何确定 NSURLSessionTask 的请求何时开始?

ios - Xcode 在验证时卡住

javascript - iOS Safari : Prevent (or Control) Scroll on Input Focus

ios - 原因: 'An NSManagedObject of class ' NSManagedObject' must have a valid NSEntityDescription?

cocoa - 为什么引发 NSException 不会导致我的应用程序崩溃?