我有一个我正在重构的应用程序,我只是实现了多线程,以便UI可以运行得更顺畅。在iphone模拟器中,我没有任何泄漏,但在iOS 4.2上运行的iPhone 3G上测试我得到内存泄漏。我已经做了很多搜索正确的方法来实现一个带有操作队列的自动释放池,非常感谢帮助。
我已经在我的viewcontroller中创建了一个nsoperationqueue
- (void)loadData
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSOperationQueue *queue = [NSOperationQueue new]; // creates multithread for loading data without slowing UI
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(firstRun) object:nil];
[queue addOperation:operation];
[operation release];
[queue release];
[pool release];
}
答案 0 :(得分:2)
首先,您不应该只创建然后释放队列。将该队列创建为类的ivars之一更自然,然后在视图控制器消失时释放它(您还可以取消任何挂起的操作并取消/等待任何正在运行的操作完成)。
其次,您不需要在创建操作的方法中使用自动释放池,并将其添加到队列中,因为该方法是从主线程调用的。相反,您需要从对象实际调用的方法中获取自动释放池(这可能是在另一个线程上运行的。)
因此,您可能拥有以下内容(假设您将队列命名为ivar队列_):
- (void)viewDidLoad
{
[super viewDidLoad];
if( !queue_ ) queue_ = [[NSOperationQueue alloc] init];
// other view loading code
}
- (void)loadData
{
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(firstRun) object:nil];
[queue_ addOperation:operation];
[operation release];
}
- (void)firstRun
{
// Here we may run on another thread, so 1) we need an autorelease pool; and
// 2) we need to make sure we don't do anything that requires a runloop
NSAutoreleasePool* threadPool = [NSAutoreleasePool new];
// do long-running things
[threadPool drain];
}
- (void)dealloc
{
if( queue_ ) {
[queue_ setSuspended:YES];
[queue_ cancelAllOperations];
// you need to decide if you need to handle running operations
// reasonably, but don't wait here because that may block the
// main thread
[queue_ release];
}
// other dealloc stuff
[super dealloc];
}
您还可以根据需要初始化队列,因此不是在viewDidLoad中初始化,而是检查其存在并在必要时在您添加操作的任何位置进行初始化。这可能包含在它自己的方法调用中,但是这里的延迟初始化可能不是必需的,因为队列非常轻量级。
答案 1 :(得分:0)
您应该在NSOperation将调用的方法的开头创建一个NSAutoreleasePool
(在本例中为firstRun
),并在方法结束时将其排除。