【问题标题】:How to dereference an Objective-C object via its pointer/memory address?如何通过指针/内存地址取消引用 Objective-C 对象?
【发布时间】:2015-06-17 03:03:18
【问题描述】:

所以,很容易得到一个对象指针的“内存地址”,呵呵..

id x = @"obj"; printf("'x' is at: %p", x);

'x' is at: 0x100b60048

令人惊讶的是,我似乎找不到任何关于如何执行“反向”操作的参考。 IE。通过十六进制 int 指针地址或字符串表示获取对对象指针的引用...

NSString  * ptr = @"0x100b60048";
unsigned   addr = 0;
NSScanner * scn = [NSScanner scannerWithString:ptr];
[scn scanHexInt:&addr];

我确实遇到了以下“方式”,但它 a) 不起作用(它崩溃了)并且 b) 激怒了编译器脆弱的敏感性(也就是它发出警告,哈哈)。

id z = (__bridge id)((void*)addr);

那么,什么是“正确的”、现代的、兼容 ARC 的方法呢?

【问题讨论】:

  • 我想唯一正确的方法是:不要这样做。但是我可以问一下你需要它吗?
  • 这听起来非常危险。你为什么要这样做?
  • 我确实对内容有一个真正的问题:你仍然没有解释,为什么你会传递字符串而不是指针/对象本身。如果您可以向我们展示真正的需求,我会说您的架构已损坏,应该予以修复。
  • 如果对象还不存在,你怎么知道它的地址?? (我怀疑你有一些严重的误解。)
  • @alexgray 不,通过使用地址作为字符串来表示对象然后将该字符串转换回引用不是归档、DO 或 ObjC 运行时的工作方式.当你在一个应用程序中谈论不同的应用会话、不同的机器甚至不同的文档时,从字符串到引用的转换将会失败。

标签: objective-c pointers memory-management runtime nsobject


【解决方案1】:

那么,什么是“正确的”、现代的、兼容 ARC 的方法呢?

正确的方法?不要这样做。

要使对象在 ARC 应用程序中保留在内存中,需要对所述对象进行强引用(或者您必须使用 CF API 做一些非常讨厌的事情)。并且任何字符串中的指针都只会在应用程序的生命周期内有效;退出并重新启动?现在所有地址都是假的。

所以,如果你真的想在字符串中引用一个随机对象,那么这样做:

  • 将对象放在字典中,以 NSNumber 或 NSString 作为键(您甚至可以使用对象的地址作为值,但我建议不要这样做,因为地址无法在应用程序重新启动时继续存在,而且您可能有一天会想要保留那本字典)
  • 解析字符串时,提取键并查找对象

这样,您将永远不必在 int 和 ptr 之间进行转换,您不必使用大量危险的类型转换来使编译器安静下来,并且您的代码将与 ARC 兼容。

【讨论】:

  • 我同意并同意您的所有观点。不过,我想象的理论任务......涉及“各方”,他们无法访问这样一个“共享”容器来保存实际对象。
  • @alexgray 那么所有各方都需要有一些公共密钥的概念才能访问实际对象。如果各方存在于不同的机器、不同的应用程序会话中,或者甚至存在于关闭和打开文档中,那么地址的字符串表示将不起作用
【解决方案2】:

所以这行得通。话虽如此,在我的项目中依赖它我会非常不舒服。如果该变量在您扫描其地址之前被释放,谁知道您会得到什么。在这方面,我想这违反了“ARC 兼容”标准,因为谁知道该引用何时发布,这使得这非常危险。此外,类型安全完全不在考虑范围之内。

NSString *pointer = @"test";
NSString *address = [NSString stringWithFormat:@"%p",pointer];

NSString *retrievedObject;
sscanf([address cStringUsingEncoding:NSUTF8StringEncoding], "%p", &retrievedObject);

【讨论】:

    【解决方案3】:

    好的,好吧,我确实想出了一个相对轻松的方法来做到这一点,所以我会在这里发布它以进行欺侮/吹毛求疵,甚至, ... 可能接受 ...使用原始问题的变量...

    /// this requires a "0x" formatted hex string                                              
    ptr = [ptr hasPrefix:@"0x"] ? ptr :
          [@"0x" stringByAppendingString:ptr];
    
    uintptr_t hex = strtoull(ptr.UTF8String, NULL, 0);
        id gotcha = (__bridge id)(void *)hex;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-16
      • 2013-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多