草庐IT

ios - Xcode 8.3 中奇怪的 Clang 行为

coder 2024-01-17 原文

最近我注意到 Xcode 中 Objective C 内存管理的奇怪行为。 这是代码:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSString *firstString = [[NSString alloc] initWithString: @"Hello"];
        NSString *secondString = firstString;
        [firstString release];
        NSLog(@"%@", secondString);
    }
    return 0;
}

我认为,secondString 在释放 firstStringNSLog 后指向 nil 应该会产生错误。 但是此代码不会产生任何错误并成功打印“Hello”字符串。 我用这样的命令手动编译和运行代码,也没有发现任何错误:

% clang -framework Foundation -fno-objc-arc main.m && ./a.out

我尝试使用在线 objective-c 编译器 (GCC) ( http://rextester.com/l/objectivec_online_compiler ) 编译这段代码,但出现了错误。 我究竟做错了什么? Xcode 中的 ARC 支持已关闭。 提前致谢。

最佳答案

如果您执行静态分析(Xcode 中的 shift+command+B,或 Xcode 的“Product”菜单上的“Analyze”) , 它会警告你你试图在一个对象被释放后引用它:

问题是在手动引用计数代码中,您对释放对象的引用不会自动设置为nil。因此,除非您手动 nil 这些指针,否则您最终可能会得到指向先前已释放的对象的悬空指针。

静态分析器非常擅长识别这类问题,等等。我建议您在继续之前确保静态分析器的健康状况良好。

在这种情况下,第二道防线是启用僵尸运行时调试选项。这将报告在对象被释放后与对象进行交互的任何尝试。当您编辑 Xcode 目标的方案时,可以在“诊断”部分启用 Zombies。

不幸的是,您正在使用 NSString,它不遵循典型的内存管理规则(它可以保留自己对字符串的引用,因此它们并不总是在您期望的时候被释放他们是)。

考虑一个类似于您的示例,但自定义类除外:

#import <Foundation/Foundation.h>

@interface MyObject: NSObject
@end
@implementation MyObject
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        MyObject *firstObject = [[MyObject alloc] init];
        MyObject *secondObject = firstObject;
        [firstObject release];
        NSLog(@"%@", secondObject);
    }
    return 0;
}

如果你在运行僵尸的情况下运行它,你将收到一条相应的错误消息,表明你正在尝试与已释放的实例进行交互:

2017-05-27 08:19:18.154033-0700 MyApp[36888:7215135] *** -[MyObject isProxy]: message sent to deallocated instance 0x100303620

但是你可能不会从 NSString 得到这个警告。总之,应该避免从 NSString 行为中得出任何更广泛的内存管理结论。相反,依赖 Xcode 的静态分析器和僵尸程序。 (请注意,当您完成应用程序调试后,请记得关闭僵尸程序。)

关于ios - Xcode 8.3 中奇怪的 Clang 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44216327/

有关ios - Xcode 8.3 中奇怪的 Clang 行为的更多相关文章

  1. ruby - 如何在 Lion 上安装 Xcode 4.6,需要用 RVM 升级 ruby - 2

    我实际上是在尝试使用RVM在我的OSX10.7.5上更新ruby,并在输入以下命令后:rvminstallruby我得到了以下回复:Searchingforbinaryrubies,thismighttakesometime.Checkingrequirementsforosx.Installingrequirementsforosx.Updatingsystem.......Errorrunning'requirements_osx_brew_update_systemruby-2.0.0-p247',pleaseread/Users/username/.rvm/log/138121

  2. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  3. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  4. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  5. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  6. ruby - Ruby gsub 替换中的行为不一致? - 2

    两个gsub产生不同的结果。谁能解释一下为什么?代码也可在https://gist.github.com/franklsf95/6c0f8938f28706b5644d获得.ver=9999str="\tCFBundleDevelopmentRegion\n\ten\n\tCFBundleVersion\n\t0.1.190\n\tAppID\n\t000000000000000"putsstr.gsub/(CFBundleVersion\n\t.*\.).*()/,"#{$1}#{ver}#{$2}"puts'--------'putsstr.gsub/(CFBundleVersio

  7. ruby-on-rails - Ruby 中意外的大小写行为 - 2

    我在一段非常简单的代码(如我所想)中得到了一个错误的值:org=4caseorgwhenorg=4val='H'endputsval=>nil请不要生气,我希望我错过了一些非常明显的东西,但我真的想不通。谢谢。 最佳答案 这是典型的Ruby错误。case有两种被调用的方法,一种是你传递一个东西作为分支的基础,另一种是你不传递的东西。如果您确实在case中指定了一个表达式语句然后评估所有其他条件并与===进行比较.在这种情况下org评估为false和org===false显然不是真的。所有其他情况也是如此,它们要么是真的,要么是假的。

  8. ruby - 使对象的行为类似于 ruby​​ 中并行分配的数组 - 2

    假设您在Ruby中执行此操作:ar=[1,2]x,y=ar然后,x==1和y==2。是否有一种方法可以在我自己的类中定义,从而产生相同的效果?例如rb=AllYourCode.newx,y=rb到目前为止,对于这样的赋值,我所能做的就是使x==rb和y=nil。Python有这样一个特性:>>>classFoo:...def__iter__(self):...returniter([1,2])...>>>x,y=Foo()>>>x1>>>y2 最佳答案 是的。定义#to_ary。这将使您的对象被视为要分配的数组。irb>o=Obje

  9. ruby - 为什么不能使用类IO的实例方法noecho? - 2

    print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上

  10. ruby - 了解在 Ruby 中与 lambda 一起使用的 inject 行为 - 2

    我经常将预配置的lambda插入可枚举的方法中,例如“map”、“select”等。但是“注入(inject)”的行为似乎有所不同。例如与mult4=lambda{|item|item*4}然后(5..10).map&mult4给我[20,24,28,32,36,40]但是,如果我制作一个2参数lambda用于像这样的注入(inject),multL=lambda{|product,n|product*n}我想说(5..10).inject(2)&multL因为“inject”有一个可选的单个初始值参数,但这给了我......irb(main):027:0>(5..10).inject

随机推荐