【问题标题】:Why GNUstep NSRunLoop quits immediately with ARC?为什么 GNUstep NSRunLoop 立即退出 ARC?
【发布时间】:2013-10-15 19:47:30
【问题描述】:

我正在尝试 GNUstep。如果它运作良好,我会尝试用它做一个网站。 无论如何,我从一开始就被困住了。 GNUstep NSRunLoop 的实现似乎效果不佳。

这是我的代码。

#import <Foundation/Foundation.h>

@interface  AAA : NSObject
- (void)test1:(id)s;
@end
@implementation AAA
- (void)test1:(id)s
{
    NSLog(@"%@", s);
}
- (void)dealloc
{
    NSLog(@"DEALLOCED!!");
}
@end


int main(int argc, const char * argv[])
{
    @autoreleasepool
    {
        AAA*    aaa =   [[AAA alloc] init];
        [[NSNotificationCenter defaultCenter] addObserver:aaa selector:@selector(test1:) name:NSFileHandleDataAvailableNotification object:nil];

        [[NSFileHandle fileHandleWithStandardInput] waitForDataInBackgroundAndNotify];
        [[NSRunLoop currentRunLoop] run];
    }
    return 0;
}

我用这个命令构建了这段代码。

clang -v
EE_GNUSTEP_OPTS="-MMD -MP -DGNUSTEP -DGNUSTEP_BASE_LIBRARY=1 -DGNU_RUNTIME=1 -DGNUSTEP_BASE_LIBRARY=1 -fno-strict-aliasing -fexceptions -fobjc-exceptions -D_NATIVE_OBJC_EXCEPTIONS -D_NONFRAGILE_ABI -pthread -fPIC -Wall -DGSWARN -DGSDIAGNOSE -Wno-import -g -fgnu-runtime -fconstant-string-class=NSConstantString"
EE_BUILD_OPTS="-I/usr/local/include -L/usr/local/lib -lc -lobjc -lgnustep-base -fblocks -fobjc-arc -fobjc-abi-version=3"
alias OBJCC="clang $EE_GNUSTEP_OPTS $EE_BUILD_OPTS"
OBJCC *.m

在 OSX 下,程序不会退出,只是继续运行 run-loop。如果我不使用 ARC,它在 FreeBSD 上的 GNUstep 下同样有效。如果我启用 ARC,程序会立即退出。 我不知道为什么只有在启用 ARC 时这不起作用。为什么会立即退出?

这是我使用的组件版本:

svn co http://svn.gna.org/svn/gnustep/libs/libobjc2/releases/1.7 libobjc2-1.7 &
svn co http://svn.gna.org/svn/gnustep/tools/make/tags/make-2_6_5 make-2_6_5 &
svn co http://svn.gna.org/svn/gnustep/libs/base/tags/base-1_24_5 base-1_24_5 &

【问题讨论】:

    标签: nsrunloop gnustep


    【解决方案1】:

    这似乎是 GSFileHandle 类中的一个错误。 fileHandleWithStandardInput 返回的单例是自动释放的。在非 ARC 模式下,它在 @autoreleasepool 作用域的末尾被销毁,但你永远不会到达那个点,所以它工作正常。

    在 ARC 模式下,序列变成了以下几行:

        NSFileHandle *tmp = [NSFileHandle fileHandleWithStandardInput];
        objc_retainAutoreleasedReturnValue(tmp);
        [tmp waitForDataInBackgroundAndNotify];
        objc_release(tmp);
    

    在调用objc_release() 之后,对象被释放。当对象被释放时,它有助于将自身作为运行循环源删除。然后运行循环没有注册源,因此退出(否则它将永远等待)。

    这显示了 ARC 的优点之一——临时对象不会在自动释放池中花费太多时间——但在这种情况下它会发现一个错误。幸运的是,它以比不使用 ARC 更容易调试的方式发现错误(如果不使用 ARC,我们会在很久以后看到当前自动释放池范围之外的东西尝试访问文件句柄时崩溃)。

    我已经在 GNUstep Base svn r37245 中修复了这个问题,感谢您的报告(将来,如果将 GNUstep 错误报告发布到 GNUstep 邮件列表而不是随机的第三方网站,则更有可能看到,但是...)。

    【讨论】:

    • 感谢您解决此问题。我会等待下一个版本。我也将其发布到邮件列表以确认为错误,但我认为我的邮件目前正在审核中。