NSLog 实际上是做啥的?

Posted

技术标签:

【中文标题】NSLog 实际上是做啥的?【英文标题】:What does NSLog actually do?NSLog 实际上是做什么的? 【发布时间】:2010-08-21 03:58:56 【问题描述】:

我遇到了一个奇怪的问题。我在我的应用程序中使用来自 Apple 私有框架的方法。当我第一次调用它时,它起作用了。当我立即第二次调用它而没有任何中间内容时,它崩溃了。但是,如果我将 NSLog 放在两个调用之间,效果会非常好。所以我尝试删除 NSLog 并在它们之间放置 for-loops、sleep()、printf("...") 和 fprintf(stderr, "...") 以模拟 NSLog,但这没有帮助。我想知道该方法是如何知道我使用 NSLog 的?换句话说,NSLog 实际上做了什么来影响方法的行为?

非常感谢!

编辑:

我似乎解决了这个问题。我将在这里分享我的解决方案,希望它对某些人有用。

我正在使用 MultitouchSupport.framework 创建一个与多点触控相关的应用程序。我从http://aladino.dmi.unict.it/?a=multitouch 复制了代码,并在循环末尾添加了CFRelease。所以,基本上,我的主要方法是这样的:

int main(void)  
    int i; 
    NSMutableArray* deviceList = (NSMutableArray*)MTDeviceCreateList(); //grab our device list 
    for(i = 0; i<[deviceList count]; i++)  //iterate available devices 
        MTRegisterContactFrameCallback([deviceList objectAtIndex:i], touchCallback); //assign callback for device 
        MTDeviceStart([deviceList objectAtIndex:i], 0); //start sending events 
    
    CFRelease((CFMutableArrayRef)deviceList); 
    printf("Ctrl-C to abort\n"); 
    sleep(-1); 
    return 0; 

运行一段时间后,会显示“程序接收信号:“EXC_BAD_ACCESS”。” 这是堆栈跟踪:

#0 0x7fff8795496e in ParsedMultitouchFrameRepInitialize
#1 0x7fff879565b1 in mt_HandleMultitouchFrame
#2 0x7fff87955a03 in mt_DequeueDataFromDriver
#3 0x7fff87955b29 in mt_DequeueMultitouchDataFromDriverThreadEntry
#4 0x7fff831b3456 in _pthread_start
#5 0x7fff831b3309 in thread_start

但是,如果我将 NSLog 放在 MTDeviceStart 下面,它不会崩溃。

我在原始代码中添加CFRelease((CFMutableArrayRef)deviceList) 的原因是我认为从名为*Create* 或*Copy* 的函数创建的对象应该由我们自己释放。但事实证明,如果我像原始代码一样删除它,即使不使用 NSLog,它也不会崩溃。

所以,也许是因为我发布deviceList 太早了?但如果是这样,为什么 NSLog 似乎能够防止崩溃呢?

【问题讨论】:

它可能与 NSLog 无关。我会发布一些代码。 请将代码和堆栈跟踪编辑到您的问题中。 您对命名约定是正确的,但由于 MTDeviceCreateList 是一个私有函数,它可能违反/不符合它。 (也许它的意思是“创建旨在在进程期间保持活动的设备数组,并返回指向它的指针”。)尝试在 Instruments 的 Zombies 工具下运行您的程序(有崩溃)。这样,您应该能够证明您的发布是否是过度发布,或者确定崩溃的真正原因。 我猜MT 函数不会保留您传递给它们的对象,因此如果您释放设备列表,它们会过早死亡。 “创建”规则是 Carbon 规则,而不是 Cocoa 规则。只有具有“alloc”、“new”和“copy”的函数将所有权传递给 Cocoa 中的调用者。 【参考方案1】:

类似的东西:

static inline void NSLogMessageString(NSString *string)
  NSString *date=[[NSDate date]
   descriptionWithCalendarFormat:@"%Y-%m-%d %H:%M:%S.%F"
                        timeZone:nil locale:nil];
  NSString *process=[[NSProcessInfo processInfo] processName];

  NSLogFormat(@"%@ %@[%d:%lx] %@",date,process,NSPlatformProcessID(),NSPlatformThreadID(),string);


void NSLogv(NSString *format,va_list arguments) 
  NSString *string=NSStringNewWithFormat(format,nil,arguments,NULL);

  NSLogMessageString(string);

 [string release];


void NSLog(NSString *format,...) 
  va_list arguments;

  va_start(arguments,format);

  NSLogv(format,arguments);

感谢您提出这个问题,哈哈,我想重写它,以便添加调试变量,这意味着我可以在需要时关闭所有 NSLogging 调用..

【讨论】:

【参考方案2】:

这需要很长时间。我不确定为什么。它打印日期/时间、进程名称、进程 ID、线程 ID 和(最后)您要求的字符串。我认为它还将日志消息发送到 syslogd(Xcode 或 iPCU 的控制台将多行 NSLogs 显示为单个条目;我忘记了);那里的 IPC 可能很重要。

尝试使用 syslog()(#import &lt;syslog.h&gt; 然后syslog(LOG_INFO, "Hello there!");,如果它有效但没有输出,请尝试更改优先级(请参阅man 3 syslog)。

【讨论】:

是的,NSLog 将消息发送到 ASL,就像 syslog 一样。我不确定您希望 syslog 有什么不同 - 只是不将其打印到 stderr?【参考方案3】:

NSLog 可能会影响您遇到的问题,因为它会影响线程执行的顺序,因为当您在后台线程中调用 NSLog 时,它必须获得对 stdout 的独占访问权限。由于这个原因,printf 调试线程的棘手问题通常会导致“heisenbugs”(即当您尝试检查它们时它们会改变行为)。

【讨论】:

【参考方案4】:

这可能是内存管理的问题:可能是无关的释放。如果您发布回溯,则可能有助于追踪问题。 (事实证明,我关注的 Twitter 上有人昨晚提到了类似的事情)。

【讨论】:

哇!非常感谢你。我尝试从我的代码中删除 CFRelease,它现在可以完美运行。我不确定为什么。我刚刚将我的代码添加到我的问题中。 注意:如果发布得太早,但无论如何都需要最终发布,这意味着它现在不是崩溃而是泄漏(即,如果是时间问题和你从一开始就有保留计数)

以上是关于NSLog 实际上是做啥的?的主要内容,如果未能解决你的问题,请参考以下文章

打开文件实际上是做啥的?

“OperationContext.Current.GetCallbackChannel”实际上是做啥的?

AFNetworking 中的 registerHTTPOperationClass 实际上是做啥的? [关闭]

ImageView android:cropToPadding,它实际上是做啥的?

VC++“排除目录”项目设置实际上是做啥的?

VST/VLD 实际上是做啥的?