在一个小型 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/