使用自身内部块崩溃没有错误

时间:2013-10-24 12:20:58

标签: ios objective-c objective-c-blocks

我有一个名为ServiceBrowser的班级。在这个类中,我有一个基于块的方法来搜索NSNetServices。

我这样称呼方法:

[_serviceBrowser discoverServicesOfType:@"_theService._tcp."
                               inDomain:@"local."
                    didDiscoverServices:^(NSArray *services) {

                        NSLog(@"Services discovered %@", services);

                        [UIView fadeView:_button toAlpha:1.0 duration:0.5 completion:nil];

                    } didRemoveServices:^(NSArray *services) {

                        NSLog(@"Services removed %@", services);

                    } failure:^(NSString *message) {

                        NSLog(@"Failure %@", message);

                    }];

如果我删除对fadeView:toAlpha:duration:completion:的呼叫,它会找到服务并将其记录下来。只有当我在这个块中使用self时,Xcode才会崩溃而没有任何错误记录到控制台。

fadeView:toAlpha:duration:completion:是UIView上的一个类别方法,它接受视图并将其淡入或淡出,这作为一个独立的方法可以正常工作。问题是当我在块中使用_button时它会崩溃。

我已对此进行过调查,我认为这是一个保留周期。从查看其他问题和博客文章,我应该在块内使用弱自我。

我尝试过使用__block id weakSelf = self;typeof(self) __weak w_self = self;,但都无法使用。

2 个答案:

答案 0 :(得分:0)

您可以尝试修改您的类,以便将self作为方法参数传递,并且该类将引用传递回块:

[_serviceBrowser discoverServicesOfType:@"_theService._tcp." inDomain:@"local." didDiscoverServices:^(NSArray *services, id sender) {
//                                                                                                                       ^^^^^^^^^ "sender" is "self"

                } didRemoveServices:^(NSArray *services) {

                } failure:^(NSString *message) {

                } fromSender:self];
//                ^^^^^^^^^^^^^^^ pass self here

类中的实现将是:

- (void)discoverServicesOfType:(NSString *)type inDomain:(NSString *)domain didDiscoverServices:^(NSArray *, id)discoveredBlock fromSender:(id)sender {
    NSMutableArray *services = [NSMutableArray array];
    // do some fancy stuff here
    discoveredBlock(services, sender);
}

Anc Ainu也可能是对的。请检查对象是否仍然存在。

答案 1 :(得分:0)

您可以尝试使用以下代码来捕获块中self的弱引用(Fooself的类。)

该块现在也需要注意,UIKit方法将在主线程上执行:

__weak Foo* weakSelf = self;
[_serviceBrowser discoverServicesOfType:@"_theService._tcp."
                               inDomain:@"local."
                    didDiscoverServices:^(NSArray *services) {
                        NSLog(@"Services discovered %@", services);
                        Foo* strongSelf = weakSelf;
                        if (strongSelf) {
                            dispatch_async(dispatch_get_main_queue(), ^{
                                [UIView fadeView:strongSelf.button 
                                         toAlpha:1.0 
                                        duration:0.5 completion:nil];
                            });
                        }
                    } didRemoveServices:^(NSArray *services) {
                         NSLog(@"Services removed %@", services);
                    } failure:^(NSString *message) {
                         NSLog(@"Failure %@", message);
                    }];

当块执行时,self应取消分配,强引用strongSelf将为nil

修改

为什么从UI元素捕获弱指针优先于捕获强指针?虽然这可能不是导致崩溃的原因,但这是一项重大改进。

强烈下面的块捕获self以证明这一点。请注意,当您直接引用ivar时,例如_button而不是通过属性self.buttonself将在块中隐式捕获,也就是说,它将一直保留到块完成之后。< / p>

现在,块的效果是,UI元素self将一直保持活动状态,直到块执行之后,无论何时发生这种情况,无论视图是否可见:用户可能拥有在此期间切换到许多其他视图和控制器。但是,self在块完成之后才会被释放。这不必要地保留了内存中的资源(可能是大图像),这些资源到目前为止还没有释放。

[_serviceBrowser discoverServicesOfType:@"_theService._tcp."
                               inDomain:@"local."
                    didDiscoverServices:^(NSArray *services) {
                        NSLog(@"Services discovered %@", services);
                        dispatch_async(dispatch_get_main_queue(), ^{
                            [UIView fadeView:self.button 
                                     toAlpha:1.0 
                                    duration:0.5 completion:nil];
                        });
                    } didRemoveServices:^(NSArray *services) {
                         NSLog(@"Services removed %@", services);
                    } failure:^(NSString *message) {
                         NSLog(@"Failure %@", message);
                    }];