【问题标题】:iPhone app crash when converting formatted NSString to UTF8 char *将格式化的 NSString 转换为 UTF8 字符时 iPhone 应用程序崩溃 *
【发布时间】:2010-10-15 18:14:34
【问题描述】:

我想将 NSString 转换为 const char * 以访问 sqlite DB。

这行得通:

NSString *queryStatementNS = @"select title from article limit 10";
const char *queryStatement = [queryStatementNS UTF8String];

这会导致模拟器崩溃(没有任何堆栈跟踪):

NSString *queryStatementNS = [NSString stringWithFormat:@"select title from article limit %d", 10];
const char *queryStatement = [queryStatementNS UTF8String];

谁能告诉我,StringWithFormat 方法在转换为 UTF8(或使用 cStringUsingEncoding:NSASCIIStringEncoding 转换为 ASCII)时发生了哪些变化?当根本没有向 stringWithFormat 传递任何参数时,也会发生同样的崩溃。会不会和内存管理有关?

【问题讨论】:

  • stringWithFormat 调用的位置或方法是否与 UTF8String 方法不同?如果是这样,则第二个示例中的自动释放对象 queryStatementNS 可能已被释放。第一个示例使用一个常量,它不是自动释放对象。
  • 这一切都在一个地方,就像在示例中一样。但是,我添加了一个 [queryStatementNS 保留];在这两行之间,现在它可以工作了。

标签: iphone objective-c xcode


【解决方案1】:

来自文档:

自动返回的 C 字符串 就像返回的对象一样被释放 被发布;你应该复制C 如果需要将其存储在外部,则为字符串 的自动释放上下文,其中 创建 C 字符串。

您的问题是,当 queryStatementNS 被释放时,queryStatement 正在被释放,并且由于 queryStatementNS 是自动释放的,您不知道这将在何时发生。您可以通过调用保留 queryStatementNS

[queryStatementNS retain]

在该函数的某个时刻(记得在您想放弃所有权时释放它),您可以明确地创建一个非自动释放的字符串来处理您自己,通过说

NSString* query = [[NSString alloc] initWithFormat:@"a string! %d", 10, nil]

(顺便说一句,注意 nil - 如果你没有它,xcode 会给你一个丢失的前哨警告)

或者您可以将 [queryStatementNS UTF8String] 的输出复制到您的 const char* queryStatement,就像在纯 C 中一样,使用 strcopy 或其他方式。

您给出的第一个示例继续有效的原因是您正在设置一个指向字符串文字的指针,@"select title from article limit 10"。目标 c 编译器确保内存中只有一个该字符串的实例,无论您在代码中引用它多少次。因此,它不遵守目标 c 的标准内存管理约定,并且您的指针在自动释放的上下文之外仍然有效。

【讨论】:

  • 感谢您的回答,我明天会尝试采用我的代码。当您来自 Java 时,整个内存分配和释放都令人困惑(我最后一次在 12 年前编写 C 代码......)。如果我在我的 .h 文件中声明 NSString 并在其上声明 @parameter(nonatomic,retain) 是否也能解决我的问题?我认为我必须手动释放queryStatementNS,因为我在我的方法中本地定义它并且不知道这里的自动释放概念。我真的需要阅读更多关于这个分配/保留/释放的东西。谢谢!
  • 是的,保留 NSString 作为实例变量可以解决您的问题。一定要在dealloc方法中释放!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-10
  • 1970-01-01
  • 2020-04-21
  • 2010-11-30
相关资源
最近更新 更多