Objective c 访问已发布的NSString不会';不要让应用程序崩溃

Objective c 访问已发布的NSString不会';不要让应用程序崩溃,objective-c,ios,xcode,Objective C,Ios,Xcode,我知道这可能与Stackoverflow上的问题完全相反,但今天我遇到了一些非常奇怪的事情。 我试图向某人展示如何使用仪器和NSZombies,所以我尝试创建一个崩溃 我声明了一个NSString,发布了它,然后尝试访问它,但应用程序没有崩溃 NSString* test = [[NSString alloc] init]; [test release]; NSlog(@"%@", test); 我甚至试过两次发布它,但它仍然没有使应用崩溃,它只是打印了空值 谁能解释一下我做错了什么,或者我的

我知道这可能与Stackoverflow上的问题完全相反,但今天我遇到了一些非常奇怪的事情。 我试图向某人展示如何使用仪器和NSZombies,所以我尝试创建一个崩溃

我声明了一个NSString,发布了它,然后尝试访问它,但应用程序没有崩溃

NSString* test = [[NSString alloc] init];
[test release];
NSlog(@"%@", test);
我甚至试过两次发布它,但它仍然没有使应用崩溃,它只是打印了空值

谁能解释一下我做错了什么,或者我的逻辑缺陷在哪里

多谢各位


编辑:我也尝试过类似的东西,但仍然没有崩溃

NSString* test = [[NSString alloc] init];
test = @"something";
NSlog(@"%@", test);
[test release];
NSlog(@"%@", test);

我甚至添加了两个连续的版本,一个test=nil;发布后,只是为了确保。

NSString
有时可能会表现得异常

在您的示例中,您分配了一个不带数据的
NSString

这就是它没有崩溃的原因

在没有数据的情况下分配
NSString
没有意义,因为
NSString
对象是不可变的。
在这种情况下,
NSString
将返回一种
singleton
实例,这意味着您不能释放它(当然可以,但它不会产生任何效果)。
每次以这种方式分配
NSString
对象时,都会返回相同的实例

请尝试以下方法:

NSString * test = [ [ NSString alloc ] initWithCString: "hello, world" encoding: NSUTF8StringEncoding ];

[ test release ];

NSLog( @"%@", test );
然后它会崩溃,就像预期的那样

为了证明我前面解释的内容,请尝试以下方法:

NSString * test1 = [ [ NSString alloc ] init ];
NSString * test2 = [ [ NSString alloc ] init ];

NSLog( @"OK: %p %p", test1, test2 );
您可以看到打印的地址相同,这意味着只分配了一个对象(“单例”对象,用于
NSString
没有数据的对象)

编辑

我在您的评论中看到,您试图“给字符串一个值”
这不可能使用
NSString
,因为它们是不可变的

我猜你试过这个:

NSString * s = [ [ NSString alloc ] init ];

s = @"hello, world";
在这种情况下,您没有给出值

您正在重新分配指针

这意味着您的
s
变量(指针)将指向另一个字符串对象。
这也意味着您将无法访问以前分配的字符串,因为您刚刚丢失了指向它的指针

如果需要可以更改的字符串对象,请查看
NSMutableString
类。

但请记住,更改指针值与更改对象值不同

如果您查看分配了
@“some_string”
[[NSString alloc]init]
NSString
上的
重新计数
,您将看到它是
-1
。这是因为编译器在编译时已经知道对象是什么,并设法将其存储为文本。所以当你释放它的时候,它实际上不会做任何事情。它不是一个在运行时分配的对象——它只是始终存在于应用程序二进制文件中

通过在Mac上执行以下操作,可以使崩溃发生:

#import <Foundation/Foundation.h>

int main(int argc, char** argv) {
    NSString *test = [[NSString alloc] initWithCString:argv[0] encoding:NSASCIIStringEncoding];
    NSLog(@"test = %p", test);
    [test release];
    NSLog(@"test = %p", test);
    [test release];
    NSLog(@"test = %p", test);
    return 0;
}

请注意,它也不会崩溃,它只打印出
test=0x183
3次

首先,在您的发布和您的
NSLog
之间没有发生任何其他会修改存储字符串的内存的事情,因此它碰巧仍然完好无损。你不能相信这一点


其次,系统对
[[NSString alloc]init]
有一个特例。它返回一个类型为
\uu NSCFConstantString
的预定义对象,该对象永远不会被释放。如果您打印它的引用计数,您将看到它是2147483647(0x7fffffff)。这是一个神奇的数字,表示任何保留或释放对象的尝试都会被忽略。

该NSString可能被其他人保留(请检查重新计数)。很抱歉,我试图添加新行,但我错误地按了enter键,导致问题过急。如果你够客气的话,你能把我的问题再读一遍吗?感谢您并为我的错误感到抱歉关闭ARC,我打赌这会导致您的崩溃。这不是ARC问题,因为他使用的是显式的
释放
调用,在ARC下是禁止的。调用
[[NSString alloc]init]
很可能会返回一个单例对象,这意味着您不能过度释放它。您应该尝试确保有一个一次性对象,比如
[[NSMutableString alloc]init]
。在对象的创建/销毁周围包装一个自动释放池也是值得的,以防在幕后发生任何自动释放。谢谢,我明天会在工作中尝试这个,并接受它崩溃的答案:))奇怪的事情也在使用数据进行尝试。我分配字符串,给它一个值,然后打印它。然后将其释放并再次打印。它打印为空,但应用程序没有崩溃。你在叫什么“给一个值”?正如我所说,NSString对象是不可变的。所以我想你只是把指针分配给了另一个有效的实例。。。在这种情况下,您没有更改对象的值,而是将指向原始对象的指针指定给另一个对象;哇,现在我觉得自己真的很蠢。。为我辩护,我只有4个月的objective-c经验。不管怎样,我今天学到了一些新东西,谢谢!我真的很感激你把一切解释得如此透彻。没问题,很高兴知道你现在清楚地理解了这一切。快乐编码!:)我还尝试使用test=nil;发布后,只是为了确保它不会以那种方式崩溃。明天上班时我会试试你的建议。谢谢你的帮助和解释!我真的很感激
#import <Foundation/Foundation.h>

int main(int argc, char** argv) {
    NSNumber *test = [[NSNumber alloc] initWithInt:1];
    NSLog(@"test = %p", test);
    [test release];
    NSLog(@"test = %p", test);
    [test release];
    NSLog(@"test = %p", test);
    return 0;
}