iOS - 我应该在这个区块中调用“weakSelf”吗?

时间:2015-12-15 03:43:59

标签: ios objective-c memory-management

好的,所以当我在块中使用weakSelf时,我可能还没有完全掌握。我知道这是为了防止保留周期而不是,但我听说这个规则有一些例外。

在下面的代码中,我检查API调用是否因登录会话到期而失败,然后我尝试重新验证用户并通过调用{{1}重试因此问题而失败的API请求在重新认证方法的成功块中:

[self sendTask:request successCallback:success errorCallback:errorCallback];

这种不良做法是否会导致保留周期?如果是这样,为什么?假设我事先/*! * @brief sends a request as an NSHTTPURLResponse. This method is private. * @param request The request to send. * @param success A block to be called if the request is successful. * @param error A block to be called if the request fails. */ -(void)sendTask:(NSURLRequest*)request successCallback:(void (^)(NSDictionary*))success errorCallback:(void (^)(NSString*))errorCallback { NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { [self parseResponse:response data:data successCallback:success errorCallback:^(NSString *error) { //if login session expired and getting "not authenticated" error (status 401) NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response; if (httpResp.statusCode == 401) { NSLog(@"NOT AUTHENTICATED THO"); AuthenticationHelper* auth = [AuthenticationHelper sharedInstance]; NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; //attempt to re-authenticate the user [AuthenticationHelper loginUser:[defaults stringForKey:@"username"] password:[defaults stringForKey:@"password"] successCallback:^(User* u) { auth.loggedInUser = u; NSLog(@"RE-AUTHENTICATION BUG FIX SUCCEEDED"); //attempt to re-try the request that failed due to [self sendTask:request successCallback:success errorCallback:errorCallback]; } errorCallback:^(NSString *error) { NSLog(@"RE-AUTHENTICATION BUG FIX FAILED"); }]; } else { errorCallback(error); } }]; }]; [task resume]; } ,我应该使用[weakSelf sendTask:request successCallback:success errorCallback:errorCallback];吗?

2 个答案:

答案 0 :(得分:2)

在此示例中,没有保留周期,因为self不持有对块的引用。当块完成时,它将释放它在self上的保留,如果这是最后一个引用,则实例将被解除分配,就像您期望的那样。

答案 1 :(得分:1)

保留周期肯定是强引用的一个风险,尽管我认为它不适用于这种情况。在这些回调中对self的强引用可能会延长self对象的生命周期,直到它们完成,但看起来这些块一旦被调用就会被释放,或者当请求失败时,它们会释放它们的强大引用和self对象可以解除分配。

但是,您仍然可以看到这些强引用导致的意外行为。这些强引用可以使这个对象保持活着,直到这些请求完成。这可能会导致您希望在请求完成时将内存中的对象保留在内存中以及将来更改应用程序状态。

作为一个可能的例子;假设您启动其中一个请求,然后用户退出并登录到其他帐户。请求可能会失败,然后使用第二个用户帐户的凭据重试。这可能不是用户想要的结果。

在这个应用程序中实际上不可能实现,但如果您使用这样的强引用,则需要考虑它,并在每次更改应用程序与此对象交互的方式时重新考虑它。这导致一个类很难重用甚至是危险的。如果您小心使用strongweak,则可以编写一个与应用程序其余部分状态无关的类。

在这种情况下正确使用弱引用可能比您预期的要复杂一些。创建弱保留版本的self肯定是正确的第一步:

__weak __typeof__(self) weakSelf = self

这给了我们一个weakSelf,如果{/ 1}在完成块之前被解除分配,那么它将为nil,但是根据你的并发模型,它可能{{1}在执行完成块期间要取消分配。因此,我们通常希望创建一个强引用作为块中的第一个操作,这样当块开始执行时,如果self仍然存在,它将保持不变,直到块完成并且这个强引用被丢弃:

self

许多objective-c库和项目将这些语句提取到self__strong __typeof__(self) strongSelf = weakSelf宏中,这可能会有所帮助。