1

我有一个名为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;没有工作。

4

2 回答 2

0

您可以尝试以下代码来捕获self块内的弱引用(Foo是 的类self)。

该块现在还需要注意,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而不是通过 property self.buttonself将在块中隐式捕获,也就是说,它将一直保留到块完成后。

现在,块的效果是,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);
                    }];
于 2013-10-24T13:21:26.830 回答
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 也可能是对的。请检查对象是否仍然存在。

于 2013-10-24T12:32:45.737 回答