从块管理 C 字符串,NSAlert,OS X
managing C-strings from blocks, NSAlert, OS X
我写了一段测试代码 "AlertTest" 以确保我以正确的方式实现 NSAlert 对象。它由一个触发 [doSomething: cstr] 打印 C 字符串的按钮和一个发布警报的方法组成,该方法将相同的字符串传递给相同的方法,但从完成内部处理程序。
这是调试器控制台打印输出:
-来自 [buttonPressed]
2015-01-09 18:28:09.832 AlertTest[1260:40881] Application must quit
Application must quit
-来自[mPostError:cstr]
2015-01-09 18:28:12.276 AlertTest[1260:40881] @Èø_ˇ
@17_7
我对如何从完成处理程序中正确传递字符串感到困惑。没有报告编译器错误。我一定错过了一些非常明显的东西。提前致谢。这是代码:
//___________________________________________________________
- (IBAction)buttonPressed:(NSButton *)sender {
char cstr[256];
strcpy(cstr, "Application must quit");
[self mDoSomething:cstr];
[self mPostError:cstr];
}
//___________________________________________________________
-(void)mDoSomething: (char*)cstr
{
NSLog(@"%s",cstr);
printf("%s\n", cstr);
}
//___________________________________________________________
-(void) mPostError: (char *)cstr
{
char cMessage[64] = "Critical Error";
NSString *message = [NSString stringWithCString:cMessage encoding:NSASCIIStringEncoding];
NSString *infoText = [NSString stringWithCString:cstr encoding:NSASCIIStringEncoding];
NSAlert* mAlert = [[NSAlert alloc] init];
[mAlert setMessageText:message];
[mAlert setInformativeText:infoText];
[mAlert setAlertStyle: NSCriticalAlertStyle];
[mAlert beginSheetModalForWindow:self.window completionHandler:^(NSModalResponse returnCode) {
[self mDoSomething: cstr]; //this is the suspect line!
}];
}
您的问题与 C 字符串无关,而是与变量 lifetime.
您的执行流程如下:
buttonPressed:
被调用。这将创建一个局部变量 cstr
并调用 mPostError:
mPostError:
被调用。这调用 beginSheetModalForWindow:completionHandler:
传递给它一个块。该块引用 cstr
,因此复制了 cstr
中的值,该值是 buttonPressed:
的同名局部变量的地址。
mPostError:
returns 这让我们回到...
buttonPressed:
进而 returns 销毁 其局部变量 cstr
。传递给 beginSheetModalForWindow:completionHandler:
的块现在具有指向已释放内存的地址。
用户关闭警报并调用块。该块调用 mDoSomething:
将其传递给 现在无效 地址。
mDoSomething:
调用 printf
试图将传递地址处的内存解释为 C 字符串,但现在内存已被重新用于其他用途它会产生你看到的废话。
传递 C 字符串不是问题,但是传递给块的任何值(在本例中为 char *
值)在执行块时必须有效。
您可以 "fix" 通过将 cstr
设为全局变量来解决示例中的问题:
char cstr[256]; // global
- (IBAction)buttonPressed:(NSButton *)sender {
strcpy(cstr, "Application must quit");
现在cstr
总是存在,因此块复制的地址总是有效的。
当然你现在也永久用完了 256 字节的内存,如果这个字符串只在短时间内需要,那就是(小)浪费。
在您的实际代码中,这可能不是问题 - C 字符串可能已经被管理,因此它们可以根据需要存在。如果不是,并且需要使用 C 字符串,那么您可能需要考虑动态分配它们(参见 malloc
和朋友)并在不再需要时释放它们(参见 free
)。
HTH
我写了一段测试代码 "AlertTest" 以确保我以正确的方式实现 NSAlert 对象。它由一个触发 [doSomething: cstr] 打印 C 字符串的按钮和一个发布警报的方法组成,该方法将相同的字符串传递给相同的方法,但从完成内部处理程序。 这是调试器控制台打印输出:
-来自 [buttonPressed]
2015-01-09 18:28:09.832 AlertTest[1260:40881] Application must quit
Application must quit
-来自[mPostError:cstr]
2015-01-09 18:28:12.276 AlertTest[1260:40881] @Èø_ˇ
@17_7
我对如何从完成处理程序中正确传递字符串感到困惑。没有报告编译器错误。我一定错过了一些非常明显的东西。提前致谢。这是代码:
//___________________________________________________________
- (IBAction)buttonPressed:(NSButton *)sender {
char cstr[256];
strcpy(cstr, "Application must quit");
[self mDoSomething:cstr];
[self mPostError:cstr];
}
//___________________________________________________________
-(void)mDoSomething: (char*)cstr
{
NSLog(@"%s",cstr);
printf("%s\n", cstr);
}
//___________________________________________________________
-(void) mPostError: (char *)cstr
{
char cMessage[64] = "Critical Error";
NSString *message = [NSString stringWithCString:cMessage encoding:NSASCIIStringEncoding];
NSString *infoText = [NSString stringWithCString:cstr encoding:NSASCIIStringEncoding];
NSAlert* mAlert = [[NSAlert alloc] init];
[mAlert setMessageText:message];
[mAlert setInformativeText:infoText];
[mAlert setAlertStyle: NSCriticalAlertStyle];
[mAlert beginSheetModalForWindow:self.window completionHandler:^(NSModalResponse returnCode) {
[self mDoSomething: cstr]; //this is the suspect line!
}];
}
您的问题与 C 字符串无关,而是与变量 lifetime.
您的执行流程如下:
buttonPressed:
被调用。这将创建一个局部变量cstr
并调用mPostError:
mPostError:
被调用。这调用beginSheetModalForWindow:completionHandler:
传递给它一个块。该块引用cstr
,因此复制了cstr
中的值,该值是buttonPressed:
的同名局部变量的地址。mPostError:
returns 这让我们回到...buttonPressed:
进而 returns 销毁 其局部变量cstr
。传递给beginSheetModalForWindow:completionHandler:
的块现在具有指向已释放内存的地址。用户关闭警报并调用块。该块调用
mDoSomething:
将其传递给 现在无效 地址。mDoSomething:
调用printf
试图将传递地址处的内存解释为 C 字符串,但现在内存已被重新用于其他用途它会产生你看到的废话。
传递 C 字符串不是问题,但是传递给块的任何值(在本例中为 char *
值)在执行块时必须有效。
您可以 "fix" 通过将 cstr
设为全局变量来解决示例中的问题:
char cstr[256]; // global
- (IBAction)buttonPressed:(NSButton *)sender {
strcpy(cstr, "Application must quit");
现在cstr
总是存在,因此块复制的地址总是有效的。
当然你现在也永久用完了 256 字节的内存,如果这个字符串只在短时间内需要,那就是(小)浪费。
在您的实际代码中,这可能不是问题 - C 字符串可能已经被管理,因此它们可以根据需要存在。如果不是,并且需要使用 C 字符串,那么您可能需要考虑动态分配它们(参见 malloc
和朋友)并在不再需要时释放它们(参见 free
)。
HTH