简体   繁体   中英

Method swizzle not working on iOS 10.1

I want to swizzle the method @property string in UIPasteboard :

+ (void) load {
    ....
    [UIPasteboard jr_swizzleMethod:@selector(string) withMethod:@selector(stringSwizzle) error:nil];
    [UIPasteboard jr_swizzleMethod:@selector(setString:) withMethod:@selector(setStringSwizzle:) error:nil];
    ....
}

When I called [[UIPasteboard generalPasteboard] setString:@"test"]; it enter my swizzle method. It works on iOS 7, iOS 8, and iOS 9. However, it failed on iOS 10.

The assembly is differnt of a test method:

- (void) pasteboradTest {
    [aUIPasteboard setString:@"test"];
}

on iOS 9:

    0xced0a <+0>:  push   {r7, lr}
    0xced0c <+2>:  mov    r7, sp
    0xced0e <+4>:  sub    sp, #0x8
    0xced10 <+6>:  movw   r2, #0xa51c
    0xced14 <+10>: movt   r2, #0x0
    0xced18 <+14>: add    r2, pc
    0xced1a <+16>: movw   r3, #0xa2e2
    0xced1e <+20>: movt   r3, #0x0
    0xced22 <+24>: add    r3, pc
    0xced24 <+26>: ldr    r3, [r3]
    0xced26 <+28>: movw   r9, #0xbc8e
    0xced2a <+32>: movt   r9, #0x0
    0xced2e <+36>: add    r9, pc
    0xced30 <+38>: movw   r12, #0xc298
    0xced34 <+42>: movt   r12, #0x0
    0xced38 <+46>: add    r12, pc
    0xced3a <+48>: str    r0, [sp, #0x4]
    0xced3c <+50>: str    r1, [sp]
    0xced3e <+52>: ldr.w  r0, [r12]
    0xced42 <+56>: ldr.w  r1, [r9]
    0xced46 <+60>: blx    r3
    0xced48 <+62>: add    sp, #0x8
    0xced4a <+64>: pop    {r7, pc}

on iOS 10:

    0x10008f78c <+0>:  stp    x29, x30, [sp, #-16]!
    0x10008f790 <+4>:  mov    x29, sp
    0x10008f794 <+8>:  sub    sp, sp, #16               ; =16 
    0x10008f798 <+12>: adrp   x8, 9
    0x10008f79c <+16>: add    x8, x8, #592              ; =592 
    0x10008f7a0 <+20>: adrp   x9, 11
    0x10008f7a4 <+24>: add    x9, x9, #3480             ; =3480 
    0x10008f7a8 <+28>: adrp   x10, 12
    0x10008f7ac <+32>: add    x10, x10, #1776           ; =1776 
    0x10008f7b0 <+36>: str    x0, [sp, #8]
    0x10008f7b4 <+40>: str    x1, [sp]
    0x10008f7b8 <+44>: ldr    x10, [x10]
    0x10008f7bc <+48>: ldr    x1, [x9]
    0x10008f7c0 <+52>: mov    x0, x10
    0x10008f7c4 <+56>: mov    x2, x8
    0x10008f7c8 <+60>: bl     0x100094cb8               ; symbol stub for: objc_msgSend
    0x10008f7cc <+64>: mov    sp, x29
    0x10008f7d0 <+68>: ldp    x29, x30, [sp], #16
    0x10008f7d4 <+72>: ret

UIPasteboard become a class cluster in iOS 10. The easiest way to notice that is to stop on breakpoint in your app and perform following command in lldb:

(lldb) po [UIPasteboard generalPasteboard]
<_UIConcretePasteboard: 0x6000000087a0>

That's the reason why swizzling doesn't work - you change implementation in UIPasteboard class, but your application invokes implementation of _UIConcretePasteboard private subclass.

You may try to workaround this issue with following code:

+ (void) load {
    // ....
    [[[UIPasteboard generalPasteboard] class] jr_swizzleMethod:@selector(string) withMethod:@selector(stringSwizzle) error:nil];
    [[[UIPasteboard generalPasteboard] class] jr_swizzleMethod:@selector(setString:) withMethod:@selector(setStringSwizzle:) error:nil];
    // ....
}

Of course, it's not the safe way to implement swizzling for class cluster - there is no any guarantee that you will not encounter any other private UIPasteboard subclass in runtime.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM