【问题标题】:Can't get custom @protocol working on iOS无法在 iOS 上使用自定义 @protocol
【发布时间】:2011-07-21 08:34:43
【问题描述】:

注意:以下使用启用了自动引用计数 (ARC) 的 iOS。我认为 ARC 可能与它无法正常工作的原因有很大关系,因为这是根据我通过 google 找到的示例进行设置的。

我正在尝试创建一个协议来通知委托人用户从 UITableView 中选择的文件名。

FileListViewController.h

@protocol FileListDelegate <NSObject>
- (void)didSelectFileName:(NSString *)fileName;

@end

@interface FileListViewController : UITableViewController
{
    @private
        NSArray *fileList;
        id <FileListDelegate> delegate;
}
@property (nonatomic, retain) NSArray *fileList;
@property (nonatomic, assign) id <FileListDelegate> delegate;

@end

FileListViewController.m

#import "FileListViewController.h"

@implementation FileListViewController

@synthesize fileList;
@synthesize delegate;

这会在

处给出错误
@synthesize delegate;

行是“FileListViewController.m:错误:自动引用计数问题:unsafe_unretained 属性 'delegate' 的现有 ivar 'delegate' 必须是 __unsafe_unretained”

如果我更改 FileListViewController.h 并将 __weak 和 (weak) 然后它会运行。

@protocol FileListDelegate <NSObject>
- (void)didSelectFileName:(NSString *)fileName;

@end

@interface FileListViewController : UITableViewController
{
    @private
        NSArray *fileList;
        __weak id <FileListDelegate> delegate;
}
@property (nonatomic, retain) NSArray *fileList;
@property (weak) id <FileListDelegate> delegate;

@end

但是当我尝试设置委托时,应用程序崩溃了。一个名为“ImportViewController”的视图正在从“FileListViewController”创建一个视图并将委托设置为自身(ImportViewController),这样我就可以实现“didSelectFileName”的自定义协议。我得到的错误是;

* 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“-[ImportViewController setDelegate:]:无法识别的选择器已发送到实例 0x6c7d430”

我正在运行的代码是;

ImportViewController.m

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    FileListViewController *fileListViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"filelist"];

    [fileListViewController setDelegate:self];
    [self.navigationController pushViewController:fileListViewController animated:YES];

}

我的问题是:

  • 为什么把 (weak) 和 __weak 放进去让它工作?我不 理解为什么这行得通,因为我发现它在谷歌上搜索并且没有 解释。
  • 为什么我不能使用这个设置我的委托 '[fileListViewController setDelegate:self];' ?这似乎是 编译器不知道“委托”存在。

【问题讨论】:

    标签: objective-c cocoa-touch protocols


    【解决方案1】:

    在 ARC 下,ivars 默认为 strong。所以错误

    Automatic Reference Counting Issue: Existing ivar 'delegate' for unsafe_unretained property 'delegate' must be __unsafe_unretained"
    

    告诉您,您已经声明了具有__unsafe_unretained(分配)所有权的属性,其中基础 ivar 具有 __strong 所有权,这是非法的。为避免该错误,您有 3 个选项:

    1. 省略 ivar。没有必要为综合属性声明 ivar。 ivar 将隐式声明,其所有权与您的财产相匹配。
    2. 定义 ivar 以匹配您的(分配)属性声明:__unsafe_unretained id &lt;FileListDelegate&gt; delegate;
    3. 定义属性以匹配 ivar 的隐式 __strong 所有权:@property (weak) id &lt;FileListDelegate&gt; delegate;

    就我个人而言,我会省略 ivar 声明,这样您就可以在属性声明的一个地方拥有所有权语义。

    【讨论】:

      【解决方案2】:

      好像有:

      FileListViewController *fileListViewController =
          [self.storyboard instantiateViewControllerWithIdentifier:@"filelist"];
      

      您没有得到FileListViewController 对象。看看它说的消息:

      -[ImportViewController setDelegate:]: unrecognized selector sent to instance 0x6c7d430

      这就是您的应用崩溃的原因。还要尝试定义一个保留属性,而不是仅仅分配,以防委托在其他地方被释放,您的应用不会崩溃。

      【讨论】:

      • 谢谢。 instantiateViewControllerWithIdentifier:@"filelist" 确实返回了错误的控制器。
      【解决方案3】:

      我刚刚遇到了同样的问题,迫使我最终深入研究 ARC 文档。

      还可以尝试定义一个保留属性,而不仅仅是分配,以防委托在其他地方被释放,您的应用不会崩溃。

      为了澄清 user756245 的回答中的上述引用,根据我的阅读,我认为 iOS 5 并没有改变你不应该保留你的代表的最佳做法,因为这是一种很好的泄漏方式。我认为 __weak 和 (weak) 标记是编译器的注释,以便能够正确处理为委托生成代码。

      【讨论】:

        猜你喜欢
        • 2018-10-05
        • 2013-06-20
        • 1970-01-01
        • 1970-01-01
        • 2012-02-21
        • 1970-01-01
        • 2013-11-23
        • 1970-01-01
        • 2011-10-08
        相关资源
        最近更新 更多