【问题标题】:Threaded Obj-C code with ARC enabled -- why it works this way?启用 ARC 的线程化 Obj-C 代码——为什么它会这样工作?
【发布时间】:2012-10-19 20:33:35
【问题描述】:

我需要一个额外的后台线程来监听来自套接字的请求。

代码被放入单例类中;它将在 NSApplicationMain() 之前的 main.m 中调用,如下所示:

 [[SKSocketThread getSingleton] runThread];

而runThread的定义如下:

- (void) runThread {
    [NSThread detachNewThreadSelector:@selector(socketThreadMainLoop:)
                             toTarget:self
                           withObject:[self quitLock]];
}

- (void) socketThreadMainLoop:(id)param {
    NSLock *lock = (NSLock *)param;
    while (![lock tryLock]) {
        NSLog(@"Yay! We are in socketThreadMainLoop now!");
        [NSThread sleepForTimeInterval:2];
    }
    NSLog(@"Terminating the socket thread...");
    [lock unlock]; // is it really necessary?
}

编译成功,没有任何警告,但在运行时会抛出错误:

autoreleased with no pool in place.

我做了一些谷歌搜索,尝试使用 @autoreleasepool 将代码打包到 runThread 和 socketThreadMainLoop 中,但错误仍然存​​在。最后,我在 main.m 中封装了对 runThread 的调用,并且成功了!

我不知道为什么它只能这样工作......

【问题讨论】:

    标签: objective-c automatic-ref-counting


    【解决方案1】:

    您应该使用@autoreleasepool 块包装您的代码。

    ...
    - (void) socketThreadMainLoop:(id)param {
    @autoreleasepool
    {    
        NSLock *lock = (NSLock *)param;
        while (![lock tryLock]) {
            NSLog(@"Yay! We are in socketThreadMainLoop now!");
            [NSThread sleepForTimeInterval:2];
        }
        NSLog(@"Terminating the socket thread...");
        [lock unlock]; // is it really necessary?
    }
    }
    

    阅读更多: NSAutoreleasePool Class Reference

    【讨论】:

    • 它不起作用。相反,它将重复以下错误消息两次:objc[64204]: Object 0x100118a00 of class NSLock autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool() to debug objc[64204]: Object 0x100108c20 of class SKSocketThread autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool() to debug
    • 不知道是不是因为我在线程中使用了self和quitLock。
    • 嗯?他使用的是ARC,而不是GC。因此,在任何辅助线程(不直接使用运行循环)中都非常需要 @autoreleasepool{}。
    【解决方案2】:

    在objc_autoreleaseNoPool 上设置断点并发布回溯。您需要在所有不运行循环的线程中使用 @autoreleasepool{...},包括主线程(在您的 main.m 中,如果您没有调用 NSApplicationMain())。

    一些额外的反馈;您将方法命名为 getSingleton 表示您是 iOS 开发的新手(不要将方法命名为 get* 任何东西)。您在 while 循环中使用 sleep 表明您对整个网络事物也有点陌生。

    另外,在调用NSApplicationMain() 之前启动线程是完全错误的做法;您应该将网络 goop 作为应用程序启动的正常部分...见下文。

    您真的真的 真的不想使用带睡眠的手动 while() 循环进行网络连接。轮询在移动设备上是一种糟糕的模式。它很耗电,sleep 只会让事情变得无响应。

    使用适当的运行循环和/或调度源和/或 CFStream API 和/或 NSFileHandles。

    【讨论】:

    • 非常感谢您的回复。我会尝试 GCDAsyncSocket —— 看起来很有希望。
    • 我查看了回溯,发现objc_autoreleaseNoPool在我在init中设置后立即尝试获取quitLock属性时被调用,该属性由getSingleton调用(我现在将其重命名为“sharedInstance”) .甚至在我调用 runThread 启动线程之前...
    猜你喜欢
    • 1970-01-01
    • 2014-03-18
    • 2013-07-28
    • 1970-01-01
    • 2016-02-05
    • 1970-01-01
    • 2016-10-04
    • 2021-04-10
    • 2021-09-22
    相关资源
    最近更新 更多