Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 如何确保控制器在转换为ARC时保持到完成处理之后?_Objective C_Ios_Xcode4.2_Automatic Ref Counting - Fatal编程技术网

Objective c 如何确保控制器在转换为ARC时保持到完成处理之后?

Objective c 如何确保控制器在转换为ARC时保持到完成处理之后?,objective-c,ios,xcode4.2,automatic-ref-counting,Objective C,Ios,Xcode4.2,Automatic Ref Counting,我在我的应用程序中使用以下模式,并且正在过渡到ARC。基本上,对象保留控制器的一个实例,并在通过委托协议通知它已完成时释放该控制器。我不使用iVar/属性b/c startProcess可以调用N次来处理N件事情 示例如下: // start a process in a controller - (void)startProcess { MyController *controller = [[MyController alloc] init]; // set the dele

我在我的应用程序中使用以下模式,并且正在过渡到ARC。基本上,对象保留控制器的一个实例,并在通过委托协议通知它已完成时释放该控制器。我不使用iVar/属性b/c startProcess可以调用N次来处理N件事情

示例如下:

// start a process in a controller
- (void)startProcess
{
    MyController *controller = [[MyController alloc] init];
    // set the delegate, the delegate is defined as (nonatomic, assign)
    controller.delegate = self;
    [controller start];
}

// when the delegate is notified, release the controller
- (void)myControllerDidFinish:(MyController):controller
{
    // do something with results
    [controller release];
}
当上述实现转换为ARC时,
startProcess
结束后,控制器不再保留,因此不会进行处理,也不会收到委托消息

问题:当将我的项目转换为使用ARC时,如何修改上述实现以正确工作,而不在实例化控制器的对象中创建IVAR?在苹果的文档中有一个类似的例子,可以过渡到ARC,但它涉及到使用块。我不希望用完成块替换委托协议

编辑:在代码中添加了有关如何定义委托的注释


编辑:澄清第一段,解释为什么用于保存控制器的iVar/属性不起作用

为什么不创建一个
NSMutableArray
实例变量,
pendingControllers
,然后在那里添加控制器?由于数组保留其成员,因此您的代码如下所示:

// start a process in a controller
- (void)startProcess
{
    MyController *controller = [[MyController alloc] init];
    // set the delegate, the delegate is defined as (nonatomic, assign)
    controller.delegate = self;
    [controller start];

    if (pendingControllers == nil) {
        pendingControllers = [[NSMutableArray alloc] init];
    }
    [pendingControllers addObject:controller];
    [controller release];
}

// when the delegate is notified, release the controller
- (void)myControllerDidFinish:(MyController):controller
{
    // do something with results
    [pendingControllers removeObject:controller];
    if ([pendingControllers count] == 0) {
        // if ARC is enabled, remove the call to -release.
        [pendingControllers release], pendingControllers = nil;
    }
}
@interface ObjectRetainer : NSObject {
    __strong id object;
}
@property (nonatomic, strong) __strong id object;
@end

这就避免了问题。完成块是正确的答案,苹果公司正在使用它,但这种方法目前还有效。

通常,控制器有责任在完成任务时保留自己。如果控制器在后台线程上运行任务,则
NSThread
的实例应自动保留该任务。如果使用
NSURLConnection
通过网络获取数据,则应将控制器保留为
代理

如果您没有执行这样的任务,则可以在执行任务时使用合成循环保留来保留控制器。这可以通过创建一个对象来实现,我将其称为
objectreserver
,它只是有一个
\u strong id
属性。当控制器开始其任务时,它应该有一个
\u strong OBJECTCARRER
实例变量,该变量被设置为保留控制器的新的
OBJECTCARRER
。这样,控制器将保留保留控制器的
对象保持器
,从而防止其中一个被释放

当控制器完成其任务并调用了所有必要的委托方法时,它应该将
objectreserver
实例变量设置为nil。这将释放
对象夹持器
,从而释放控制器

objectreserver
界面可能如下所示:

// start a process in a controller
- (void)startProcess
{
    MyController *controller = [[MyController alloc] init];
    // set the delegate, the delegate is defined as (nonatomic, assign)
    controller.delegate = self;
    [controller start];

    if (pendingControllers == nil) {
        pendingControllers = [[NSMutableArray alloc] init];
    }
    [pendingControllers addObject:controller];
    [controller release];
}

// when the delegate is notified, release the controller
- (void)myControllerDidFinish:(MyController):controller
{
    // do something with results
    [pendingControllers removeObject:controller];
    if ([pendingControllers count] == 0) {
        // if ARC is enabled, remove the call to -release.
        [pendingControllers release], pendingControllers = nil;
    }
}
@interface ObjectRetainer : NSObject {
    __strong id object;
}
@property (nonatomic, strong) __strong id object;
@end
您应该在控制器的标题中声明一个ivar:
\uuu strong objectreserver\u reserver
。然后,在控制器的
启动
方法中:

- (void)start {
    ...
    _retainer = [[ObjectRetainer alloc] init];
    _retainer.object = self;
}
完成控制器后,只需将
\u保持器
设置为零:

- (void)performBackgroundTask {
    ....
    [delegate myControllerDidFinish:self];
    _retainer = nil;
}

更简单:使控制器成为数据成员@合成法会很神奇。

是的,我想到了,但看起来很难看。我完全支持使用块,这只是一个大项目,我试图在重写尽可能少的代码的同时转换为ARC。我还考虑在控制器中添加一个完成块,并在块中定义当前的委托处理程序。如果您觉得它不那么难看,可以使用
NSMutableSet
。无论哪种方式,您都可以解决控制器被释放的问题。+1 b/c这将起作用,但@alex的答案对我更有效。谢谢。很好,这工作做得很好!这是一种黑客行为,但实现起来很简单。我相信随着时间的推移,我会将实现更改为使用块,但现在这一切都正常工作了。