Метод swizzle не работает на iOS 10.1

Я хочу заменить метод @property string на UIPasteboard:

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

Когда я позвонил [[UIPasteboard generalPasteboard] setString:@"test"];, он ввел мой метод swizzle. Он работает на iOS 7, iOS 8 и iOS 9. Однако он не работает на iOS 10.

Сборка отличается от метода испытаний :

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

на 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}

на 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

person waitianlou    schedule 24.11.2016    source источник
comment
Какой код для sangforjr_swizzleMethod? И что вы собираетесь делать здесь в первую очередь, что требует употребления спиртных напитков?   -  person Itai Ferber    schedule 24.11.2016
comment
Это просто метод swizzle, как и те blow: method_exchangeImplementations(class_getInstanceMethod([UIPasteboard class], @selector(setString:)), class_getInstanceMethod([UIApplication class], @selector(StringSwizzle:)));, и он будет работать на [UIPasteboard generalPasteboard]   -  person waitianlou    schedule 24.11.2016
comment
Я просто установил точку останова на b [UIPasteboard setString:] b [UIPasteboard string], он не будет прерываться при выполнении кода [aUIPasteboard setString:@"test"]; и NSLog(@"%@", [aUIPasteboard string]);   -  person waitianlou    schedule 24.11.2016
comment
См. Этот ответ о различиях между ldr и ldr.w: stackoverflow.com/a/9800623/499581   -  person l'L'l    schedule 24.11.2016
comment
Спасибо, но я думаю, может, эта строка - важное место? 0x10008f7c8 <+60>: bl 0x100094cb8 , но я не очень хорошо знаком с функцией этой строки   -  person waitianlou    schedule 24.11.2016
comment
bl - это инструкция, а не функция, которая затем обычно вызывает адрес.   -  person l'L'l    schedule 24.11.2016
comment
Вы, вероятно, ищете не в том месте с этим ассемблером. Отредактируйте свой вопрос, добавив код для jr_swizzleMethod, и, вероятно, лучше всего, если вы также добавите код для двух методов замены, которые вы пытаетесь использовать. Это поможет людям помочь вам.   -  person CRD    schedule 24.11.2016
comment
@waitianlou Зачем тебе вообще эта выпивка? Что ты хочешь делать? (Какова цель обмана?) Обычно это хрупкая и неподдерживаемая практика, и вы должны стараться избегать ее везде, где это возможно, особенно в коде некоторых других фреймворков.   -  person Itai Ferber    schedule 24.11.2016
comment
Я хочу сделать что-нибудь, когда кто-нибудь попытается изменить данные UIPasteboard   -  person waitianlou    schedule 24.11.2016


Ответы (1)


UIPasteboard стать кластером классов в iOS 10. Самый простой способ заметить это - остановиться на точке останова в приложении и выполнить следующую команду в lldb:

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

Вот почему swizzling не работает - вы меняете реализацию в UIPasteboard классе, но ваше приложение вызывает реализацию _UIConcretePasteboard частного подкласса.

Вы можете попытаться решить эту проблему с помощью следующего кода:

+ (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];
    // ....
}

Конечно, это небезопасный способ реализовать swizzling для кластера классов - нет никакой гарантии, что вы не встретите какой-либо другой частный подкласс UIPasteboard во время выполнения.

person Borys Verebskyi    schedule 24.11.2016