[英]iOS 5 Twitter Framework & completionHandler block - “Capturing 'self' strongly in this block is likely to lead to a retain cycle”
我是编程和Objective-C的新手,我正在尝试解决我的代码有什么问题。 我已经阅读了一些关于块的内容,但我不知道到目前为止我所阅读的内容与我的代码有什么关系。
我的代码使用的是iOS 5 Twitter Framework。 我使用Apple提供的大多数示例代码,所以我实际上一开始并不知道我使用了一个块作为完成处理程序。
现在我从Xcode 4得到这两条消息说“ 1.块将由被捕获对象强烈保留的对象保留 ”和“ 在此块中强烈捕获'自我'可能导致保留周期 ”。
基本上,我所做的是删除Apple在其完成处理程序中使用的代码(使用TWTweetComposeViewControllerResultCancelled和TWTweetComposeViewControllerResultDone的switch语句)并使用我的if语句与[imagePickerController sourceType]
。
因此,在将图像添加到推文后调用sendTweet
。
我希望有人可以向我解释为什么会这样,以及我如何解决它。 另外:我可以将完成处理程序代码放入方法而不是块中吗?
- (void)sendTweet:(UIImage *)image
{
//adds photo to tweet
[tweetViewController addImage:image];
// Create the completion handler block.
//Xcode: "1. Block will be retained by an object strongly retained by the captured object"
[tweetViewController setCompletionHandler:
^(TWTweetComposeViewControllerResult result) {
NSString *alertTitle,
*alertMessage,
*otherAlertButtonTitle,
*alertCancelButtonTitle;
if (result == TWTweetComposeViewControllerResultCancelled)
{
//Xcode: "Capturing 'self' strongly in this block is likely to lead to a retain cycle"
if ([imagePickerController sourceType])
{
alertTitle = NSLocalizedString(@"TCA_TITLE", nil);
alertMessage = NSLocalizedString(@"TCA_MESSAGE", nil);
alertCancelButtonTitle = NSLocalizedString(@"NO", nil);
otherAlertButtonTitle = NSLocalizedString(@"YES", nil);
//user taps YES
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:alertTitle
message:alertMessage
delegate:self // Note: self
cancelButtonTitle:alertCancelButtonTitle
otherButtonTitles:otherAlertButtonTitle,nil];
alert.tag = 1;
[alert show];
}
}
基本问题是你在一个街区内使用self
。 该对象保留该块,块本身也保留该对象。 所以你有一个保留周期,因此两者都可能永远不会被释放,因为它们都有一个指向它们的引用。 Fortunaly有一个简单的解决方法:
通过对自身使用所谓的弱引用,块将不再保留对象。 然后可以释放该对象,该对象将释放该块(将MyClass
设置为适当的类型):
// before your block
__weak MyObject *weakSelf = self;
在你的块内你现在可以使用weakSelf
而不是self
。 请注意,这仅适用于使用ARC的iOS 5。
看一下这里还有一个非常好的长解释, 如何在实现API时避免在块中捕获self? 其中还介绍了如何在iOS 4和没有ARC的情况下避免这种情况。
您的块正在保留self
因为您使用self
作为UIAlertView的委托。 如果self
也保留了块,它们会相互保留,从而形成一个保留周期。
尝试
__block WhateverTypeSelfIs *nonRetainedSelfForBlock = self;
[tweetViewController setCompletionHandler:
和
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:alertTitle
message:alertMessage
delegate:nonRetainedSelfForBlock
cancelButtonTitle:alertCancelButtonTitle
otherButtonTitles:otherAlertButtonTitle,nil];
检查Apple文档 , 对象和块变量部分 。 除非使用__block,否则将保留块中引用的对象。
根据我在其他地方看到过的东西,“ 弱”对于符合ARC的代码不起作用,而且你必须使用“ _unsafe_unretained”。 这就是我在Apple示例应用程序“AVPlayerDemo”中修复“在此块中强烈捕获'自我'可能会导致保留周期”的警告:
__unsafe_unretained id unself = self;
mTimeObserver = [mPlayer addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(interval, NSEC_PER_SEC)
queue:NULL /* If you pass NULL, the main queue is used. */
usingBlock:^(CMTime time)
{
/* 'unself' replaced 'self' here: */
[unself syncScrubber];
}];
有一种相当令人惊讶的方法来摆脱警告。 请注意,只有在确定自己没有创建保留周期时才这样做,或者您确定稍后会自行解除(例如,在完成后将完成处理程序设置为nil)。 如果您可以控制界面,则重命名您的方法,使其不以“set”开头。 仅当方法名称以“set”开头时,编译器似乎才会发出此警告。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.