【问题标题】:Under ARC, is it legal/safe to assign to an object-type ivar using runtime methods?在 ARC 下,使用运行时方法分配给对象类型 ivar 是否合法/安全?
【发布时间】:2013-03-02 15:28:10
【问题描述】:

基于technique described here,我使用 ivar_getOffset() 方法在对象实例中设置 ivars。

现在我遇到了 ivar 是 NSString* 的情况:

NSString* _name;

更新:

我走错了路(在这种情况下不能使用 ivar_getOffset),我应该使用:

object_setIvar(target, _ivar, [stringValue copy]);

将对象值分配给 ivars。

我的问题仍然存在:在 ARC 下这样做是否安全? ARC 是否会正确释放 ivar 的现有对象?

我担心 ARC 可能无法正确释放 ivar 在分配之前设置的任何字符串。虽然我对此表示怀疑,否则编译器不会让我喜欢 object_setInstanceVariable 的情况(“在自动引用计数模式下不可用”) - 对吧?

【问题讨论】:

  • 你的意思是NSString** ivarPointer = ( NSString**)getIvarPointer(object, "_name");
  • 是的,我刚刚想通了。我想我在这里走错了路……
  • 是的,不知道您为什么要这样做,但我很确定如果您将其声明为 __strong NSString **ivarPointer 它将正常工作。
  • 好的,我想我只需要使用 object_setInstanceVariable 来代替 ... 分别 object_setIvar() ...
  • 好的,但我认为这不会为您提供财产释放/保留。

标签: objective-c automatic-ref-counting variable-assignment objective-c-runtime ivar


【解决方案1】:

是的,使用 ARC 这样做是合法的,至少在 Mac OS X 10.8.2 中是这样

如果你反汇编 libobjc,你会发现:

================ B E G I N   O F   P R O C E D U R E ================


                                       ; Basic Block Input Regs: rdx rsi rdi -  Killed Regs: rbx rbp r15
                                            _object_setIvar:
000000000000c1f5 55                              push       rbp                           ; XREF=0xc1e1
000000000000c1f6 4889E5                          mov        rbp, rsp
000000000000c1f9 4157                            push       r15
000000000000c1fb 4156                            push       r14
000000000000c1fd 4155                            push       r13
000000000000c1ff 4154                            push       r12
000000000000c201 53                              push       rbx
000000000000c202 4883EC18                        sub        rsp, 0x18
000000000000c206 488955C8                        mov        qword [ss:rbp-0x40+var_8], rdx
000000000000c20a 4889F3                          mov        rbx, rsi
000000000000c20d 4989FF                          mov        r15, rdi
000000000000c210 4D85FF                          test       r15, r15
000000000000c213 0F8449010000                    je         0xc362
                                       ; Basic Block Input Regs: rbx -  Killed Regs: <nothing>
000000000000c219 4885DB                          test       rbx, rbx
000000000000c21c 0F8440010000                    je         0xc362
                                       ; Basic Block Input Regs: r15 -  Killed Regs: rax
000000000000c222 41F6C701                        test       r15L, 0x1
000000000000c226 4C89F8                          mov        rax, r15
000000000000c229 740F                            je         0xc23a
                                       ; Basic Block Input Regs: <nothing> -  Killed Regs: rax
000000000000c22b 4883E00F                        and        rax, 0xf
000000000000c22f 48C1E003                        shl        rax, 0x3
000000000000c233 4803057ECE1000                  add        rax, qword [ds:0x1190b8]
                                       ; Basic Block Input Regs: rax rbx -  Killed Regs: rdx rbp rsi rdi r12
000000000000c23a 4C8B20                          mov        r12, qword [ds:rax]           ; XREF=0xc229
000000000000c23d 48C745D000000000                mov        qword [ss:rbp-0x40+var_16], 0x0
000000000000c245 4889DF                          mov        rdi, rbx
000000000000c248 E805F5FFFF                      call       _ivar_getName
000000000000c24d 488D55D0                        lea        rdx, qword [ss:rbp-0x40+var_16]
000000000000c251 4C89E7                          mov        rdi, r12
000000000000c254 4889C6                          mov        rsi, rax
000000000000c257 E8C9E7FFFF                      call       __class_getVariable
000000000000c25c 4885C0                          test       rax, rax
000000000000c25f 7433                            je         0xc294
                                       ; Basic Block Input Regs: <nothing> -  Killed Regs: r14
000000000000c261 4C8D75D0                        lea        r14, qword [ss:rbp-0x40+var_16]
000000000000c265 EB1F                            jmp        0xc286
                                       ; Basic Block Input Regs: rax rbx r12 r14 -  Killed Regs: rdx rbp rsi rdi
000000000000c267 E88EC3FFFF                      call       __class_getSuperclass         ; XREF=0xc292
000000000000c26c 488945D0                        mov        qword [ss:rbp-0x40+var_16], rax
000000000000c270 4889DF                          mov        rdi, rbx
000000000000c273 E8DAF4FFFF                      call       _ivar_getName
000000000000c278 4C89E7                          mov        rdi, r12
000000000000c27b 4889C6                          mov        rsi, rax
000000000000c27e 4C89F2                          mov        rdx, r14
000000000000c281 E89FE7FFFF                      call       __class_getVariable
                                       ; Basic Block Input Regs: rax rbx -  Killed Regs: <nothing>
000000000000c286 4839D8                          cmp        rax, rbx                      ; XREF=0xc265
000000000000c289 7409                            je         0xc294
                                       ; Basic Block Input Regs: rbp -  Killed Regs: rdi
000000000000c28b 488B7DD0                        mov        rdi, qword [ss:rbp-0x40+var_16]
000000000000c28f 4885FF                          test       rdi, rdi
000000000000c292 75D3                            jne        0xc267
                                       ; Basic Block Input Regs: rax rbx rbp -  Killed Regs: rbx rdi r12 r13
000000000000c294 4C8B6DD0                        mov        r13, qword [ss:rbp-0x40+var_16] ; XREF=0xc25f, 0xc289
000000000000c298 4889DF                          mov        rdi, rbx
000000000000c29b E8B3F2FFFF                      call       _ivar_getOffset
000000000000c2a0 4889C3                          mov        rbx, rax
000000000000c2a3 4D8D241F                        lea        r12, qword [ds:r15+rbx]
000000000000c2a7 4C89EF                          mov        rdi, r13
000000000000c2aa E8B3F2FFFF                      call       __class_usesAutomaticRetainRelease
000000000000c2af 84C0                            test       al, al
000000000000c2b1 746B                            je         0xc31e
                                       ; Basic Block Input Regs: rax r13 -  Killed Regs: rdi r14
000000000000c2b3 4C89EF                          mov        rdi, r13
000000000000c2b6 E840A00000                      call       __class_getInstanceStart
000000000000c2bb 4189C6                          mov        r14d, eax
000000000000c2be 4C89EF                          mov        rdi, r13
000000000000c2c1 E80EA80000                      call       _class_getWeakIvarLayout
000000000000c2c6 4885C0                          test       rax, rax
000000000000c2c9 7423                            je         0xc2ee
                                       ; Basic Block Input Regs: rax rbx r14 -  Killed Regs: rcx rsi rdi
000000000000c2cb 4489F1                          mov        ecx, r14d
000000000000c2ce 4889DF                          mov        rdi, rbx
000000000000c2d1 4829CF                          sub        rdi, rcx
000000000000c2d4 4889C6                          mov        rsi, rax
000000000000c2d7 E8483C0000                      call       __ZL17is_scanned_offsetlPKh   ; is_scanned_offset(long, unsigned char const*)
000000000000c2dc 84C0                            test       al, al
000000000000c2de 740E                            je         0xc2ee
                                       ; Basic Block Input Regs: rbp r12 -  Killed Regs: rsi rdi
000000000000c2e0 4C89E7                          mov        rdi, r12
000000000000c2e3 488B75C8                        mov        rsi, qword [ss:rbp-0x40+var_8]
000000000000c2e7 E82B440100                      call       _objc_storeWeak
000000000000c2ec EB74                            jmp        0xc362
                                       ; Basic Block Input Regs: rax r13 -  Killed Regs: rdi
000000000000c2ee 4C89EF                          mov        rdi, r13                      ; XREF=0xc2c9, 0xc2de
000000000000c2f1 E8C5A70000                      call       _class_getIvarLayout
000000000000c2f6 4885C0                          test       rax, rax
000000000000c2f9 7423                            je         0xc31e
                                       ; Basic Block Input Regs: rax rbx r14 -  Killed Regs: rcx rsi rdi
000000000000c2fb 4489F1                          mov        ecx, r14d
000000000000c2fe 4889DF                          mov        rdi, rbx
000000000000c301 4829CF                          sub        rdi, rcx
000000000000c304 4889C6                          mov        rsi, rax
000000000000c307 E8183C0000                      call       __ZL17is_scanned_offsetlPKh   ; is_scanned_offset(long, unsigned char const*)
000000000000c30c 84C0                            test       al, al
000000000000c30e 740E                            je         0xc31e
                                       ; Basic Block Input Regs: rbp r12 -  Killed Regs: rsi rdi
000000000000c310 4C89E7                          mov        rdi, r12
000000000000c313 488B75C8                        mov        rsi, qword [ss:rbp-0x40+var_8]
000000000000c317 E8044C0100                      call       _objc_storeStrong
000000000000c31c EB44                            jmp        0xc362
                                       ; Basic Block Input Regs: <nothing> -  Killed Regs: <nothing>
000000000000c31e 803DEB49110000                  cmp        byte [ds:_UseGC], 0x0         ; XREF=0xc2b1, 0xc2f9, 0xc30e
000000000000c325 7428                            je         0xc34f
                                       ; Basic Block Input Regs: rax r13 -  Killed Regs: rdi
000000000000c327 4C89EF                          mov        rdi, r13
000000000000c32a E8A5A70000                      call       _class_getWeakIvarLayout
000000000000c32f 4885C0                          test       rax, rax
000000000000c332 741B                            je         0xc34f
                                       ; Basic Block Input Regs: rax rbx -  Killed Regs: rsi rdi
000000000000c334 4889DF                          mov        rdi, rbx
000000000000c337 4889C6                          mov        rsi, rax
000000000000c33a E8E53B0000                      call       __ZL17is_scanned_offsetlPKh   ; is_scanned_offset(long, unsigned char const*)
000000000000c33f 84C0                            test       al, al
000000000000c341 740C                            je         0xc34f
                                       ; Basic Block Input Regs: rbp r12 -  Killed Regs: rsi rdi
000000000000c343 488B7DC8                        mov        rdi, qword [ss:rbp-0x40+var_8]
000000000000c347 4C89E6                          mov        rsi, r12
000000000000c34a E831230000                      call       _objc_assign_weak
                                       ; Basic Block Input Regs: rbx rbp r15 -  Killed Regs: rax rdx rsi rdi
000000000000c34f 488D055AE51000                  lea        rax, qword [ds:_objc_assign_ivar_internal] ; XREF=0xc325, 0xc332, 0xc341
000000000000c356 488B7DC8                        mov        rdi, qword [ss:rbp-0x40+var_8]
000000000000c35a 4C89FE                          mov        rsi, r15
000000000000c35d 4889DA                          mov        rdx, rbx
000000000000c360 FF10                            call       qword [ds:rax]
                                       ; Basic Block Input Regs: <nothing> -  Killed Regs: rbx rsp rbp r12 r13 r14 r15
000000000000c362 4883C418                        add        rsp, 0x18                     ; XREF=0xc213, 0xc21c, 0xc2ec, 0xc31c
000000000000c366 5B                              pop        rbx

注意在000000000000c2aa 调用_class_usesAutomaticRetainRelease。

此方法的实现可在opensource.apple.com获得

这个函数的标题注释是:

/***********************************************************************
 * _class_usesAutomaticRetainRelease
 * Returns YES if class was compiled with -fobjc-arc
 **********************************************************************/

这意味着 ObjC 运行时的这个特定功能知道 ARC。

【讨论】:

  • object_setIvar()的源代码也有:opensource.apple.com/source/objc4/objc4-532.2/runtime/…(比汇编代码更容易阅读,但可以确认你的答案)。
  • 请注意,这对于 __unsafe_unretained 变量将失败。它不正确地保留这些内容。
  • @RichardJ.RossIII 你确定吗?在我看来,C 代码就像分别处理弱、强和非上述代码一样。
  • @JesseRusak 是的,我确定,在这里看看这个问题:stackoverflow.com/questions/11621028/…
  • @RichardJ.RossIII 我很确定 object_setIvar 正在正确处理 __unsafe_unretained ivars。我做了一个quick test,它表明本地在存储在不安全的 ivar 中后被释放,但在被放入强 ivar 后没有。 (至少,在模拟器中使用 Xcode 4.6。)
【解决方案2】:

我不知道答案,但我知道如何确定答案...

创建一个指向您自己的类的实例的 ivar,例如 LC2DFoo。在-[LC2DFoo dealloc] 中放置一个断点。创建LC2DFoo 的实例并使用您描述的运行时方法将其分配给ivar。接下来,将相同的 ivar 设置为其他内容,例如 nil。你达到断点了吗?

【讨论】:

  • 是的,但询问 SO 更有见地。 :)
猜你喜欢
  • 2012-05-12
  • 2015-12-01
  • 2016-04-26
  • 1970-01-01
  • 2019-05-03
  • 1970-01-01
  • 2020-12-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多