简体   繁体   English

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

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

Okay so I might have not fully grasped WHEN I should use weakSelf in blocks. 好的,所以我可能还没有完全掌握什么时候我应该在块中使用weakSelf I know that it is done to prevent retain cycles and what not, but I heard there are some exceptions to this rule. 我知道这是为了防止保留周期而不是,但我听说这个规则有一些例外。

In the following code, I check to see if an API call failed due to the login session expiring, and then I attempt to re-authenticate the user and retry the API request that failed because of this issue by calling [self sendTask:request successCallback:success errorCallback:errorCallback]; 在下面的代码中,我检查API调用是否由于登录会话到期而失败,然后我尝试重新验证用户并通过调用[self sendTask:request successCallback:success errorCallback:errorCallback];重试因此问题而失败的API请求[self sendTask:request successCallback:success errorCallback:errorCallback]; in the re-authentication method's success block: 在重新认证方法的成功块中:

/*!
 * @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];
}

Is this bad practice in that it can lead to a retain cycle? 这种不良做法是否会导致保留周期? If so, why? 如果是这样,为什么? Should I instead be using [weakSelf sendTask:request successCallback:success errorCallback:errorCallback]; 我应该使用[weakSelf sendTask:request successCallback:success errorCallback:errorCallback]; assuming that I do MyAPIInterface *__weak weakSelf = self; 假设我做MyAPIInterface *__weak weakSelf = self; beforehand? 预先?

In this example there would not be a retain cycle because self isn't holding a reference to the block. 在这个例子中,没有保留周期,因为self没有持有对块的引用。 When the block completes, it will release its hold on self , and if that was the last reference, the instance will be deallocated, just as you would expect. 当块完成时,它将释放其对self保持,如果这是最后一个引用,则实例将被解除分配,就像您期望的那样。

A retain cycle is certainly one risk of strong references though I don't think it applies in this case. 保留周期肯定是强引用的一个风险,虽然我认为它不适用于这种情况。 A strong reference to self in these callbacks might extend the life of the self object until they complete but it looks like the blocks will be deallocated once called or when requests fail at which point they would release their strong references and the self object could be deallocated. 在这些回调中对self的强引用可能会延长self对象的生命周期,直到它们完成,但看起来块一旦被调用就会被释放,或者当请求失败时,它们将释放它们的强引用,并且self对象可以被释放。

You may however still see unexpected behavior resulting from these strong references. 但是,您仍然可以看到这些强引用导致的意外行为。 These strong references could keep this object alive until these requests complete. 这些强引用可以使这个对象保持活着,直到这些请求完成。 That could result in an object you expected to have been deallocated remaining in memory and changing application state far in the future when the request finishes. 这可能会导致您希望在请求完成时将某个对象保留在内存中,并在将来远程更改应用程序状态。

As one possible example; 作为一个可能的例子; suppose you start one of these requests and then the user signed out and signed into a different account. 假设您启动其中一个请求,然后用户退出并登录到其他帐户。 The request might fail and then be retried using the second user account's credentials. 请求可能会失败,然后使用第二个用户帐户的凭据重试。 That's probably not the result the user wanted. 这可能不是用户想要的结果。

Perhaps that's actually not possible in this application but if you use strong references like this you'll need to consider it, and reconsider it every time you change the way the application interacts with this object. 也许这在这个应用程序中实际上是不可能的,但如果您使用这样的强引用,则需要考虑它,并在每次更改应用程序与此对象交互的方式时重新考虑它。 That leads to a class being hard or even dangerous to reuse. 这导致一个类很难重用甚至是危险的。 If you instead make careful use of strong and weak you can write a class which does not become so coupled to the state of the rest of the application. 如果改为谨慎使用的strongweak ,你可以写一个类,它不会变得耦合到应用的静止状态。

Correct use of a weak reference in this case might be a little trickier than you expect. 在这种情况下正确使用弱引用可能比您预期的要复杂一些。 Creating a weakly retained version of self is certainly the right first step: 创建一个弱保留的self版本肯定是正确的第一步:

__weak __typeof__(self) weakSelf = self

That gives us a weakSelf which will be nil if self was deallocated before the completion block executes however depending on your concurrency model it might be possible for self to be deallocated during the execution of the completion block. 这给了我们一个weakSelf ,如果self 执行完成块之前被释放那么它将是nil,但是根据你的并发模型, 执行完成块期间可能会释放self We therefore usually want to create a strong reference as our first operation within the block so that if self still exists when the block begins executing it will remain until the block is finished and this strong reference is discarded: 因此,我们通常要创建一个有力的参考作为我们的块中第一个操作,这样,如果self当块开始执行它会一直保持到块结束,该强引用被丢弃,依然存在:

__strong __typeof__(self) strongSelf = weakSelf

A number of objective-c libraries and projects extract these statements into weakify and strongify macros which can be helpful. 许多objective-c库和项目将这些语句提取为weakifystrongify宏,这可能会有所帮助。

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

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