繁体   English   中英

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

[英]iOS - Should I be calling “weakSelf” in this block?

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

在下面的代码中,我检查API调用是否由于登录会话到期而失败,然后我尝试重新验证用户并通过调用[self sendTask:request successCallback:success errorCallback:errorCallback];重试因此问题而失败的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]; 假设我做MyAPIInterface *__weak weakSelf = self; 预先?

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

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

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

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

也许这在这个应用程序中实际上是不可能的,但如果您使用这样的强引用,则需要考虑它,并在每次更改应用程序与此对象交互的方式时重新考虑它。 这导致一个类很难重用甚至是危险的。 如果改为谨慎使用的strongweak ,你可以写一个类,它不会变得耦合到应用的静止状态。

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

__weak __typeof__(self) weakSelf = self

这给了我们一个weakSelf ,如果self 执行完成块之前被释放那么它将是nil,但是根据你的并发模型, 执行完成块期间可能会释放self 因此,我们通常要创建一个有力的参考作为我们的块中第一个操作,这样,如果self当块开始执行它会一直保持到块结束,该强引用被丢弃,依然存在:

__strong __typeof__(self) strongSelf = weakSelf

许多objective-c库和项目将这些语句提取为weakifystrongify宏,这可能会有所帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM