2013-12-09 2 views
3

В настоящее время я работаю над продуктом, который должен подменять приложение AppDelegate: didReceiveRemoteNotification: (Я не хочу вызывать свой новый метод в самом appDelegate).Можете ли вы использовать приложение для swizzle: didReceiveRemoteNotification:

Дело в том, что swizzling просто не работает. Я уже несколько раз опробовал методы с успехом, и на этот раз заменяющая реализация просто не вызывается. Мне было интересно, было ли это из-за некоторой специфики методов appDelegate, поскольку они вызываются системой, а не приложением.

+1

Я не думаю, что Apple любит вас, выполняя свои API-интерфейсы: http://stackoverflow.com/questions/7720947/method-swizzling-in-ios-5 –

+3

По определению у вас есть реализация делегата приложения в вашем собственное приложение, поэтому swizzling не нужно. Теперь, если вы говорите о swizzling ** реализации другого приложения **, то нет, вы не можете этого сделать. – bbum

+0

Не имеет смысла подмешать метод в классе, который вы определяете. Если вам не нужен код в делегате приложения, поместите его другим способом, который вы вызываете оттуда, или отправьте уведомление, которое получит какой-либо другой объект. –

ответ

3

Я собираюсь взять на себя большинство вещей, которые отсутствуют в вашем вопросе. Его отличная идея всегда ставить вопросы с образцами кода, когда это возможно.

  1. Вы должны убедиться, что вы swizzling ваши методы по конкретной реализации UIApplicationDelegate, а не самого UIApplicationDelegate. Например:

    @interface AppDelegate : UIResponder <UIApplicationDelegate> 
    @end 
    

    В этом случае вам необходимо подкачать класс AppDelegate.

  2. Также, если вы пытаетесь написать статическую библиотеку/фреймворк, вы можете вообще не знать имя этого класса. В таких случаях простейшим/безопасным способом является запрос имени AppDelegate App и его использование для извлечения определенного экземпляра класса через NSClassFromString(), или вы можете просто использовать команду для поиска нужного вам класса (поскольку обычно у вас есть класс Single AppDelegate).

    unsigned int numberOfClasses = 0; 
        Class *classes = objc_copyClassList(&numberOfClasses); 
        Class appDelegateClass = nil; 
        for (unsigned int i = 0; i < numberOfClasses; ++i) { 
         if (class_conformsToProtocol(classes[i], @protocol(UIApplicationDelegate))) { 
          appDelegateClass = classes[i]; 
         } 
    } 
    

EDIT

Есть несколько недостатков вышеуказанного подхода,

  1. Он перебирает все классы, доступные по коде приложения, пробегают по всем эти классы не являются эффективным решением.

  2. Многие известные SDK будут изучать или динамически расширять ваш AppDelegate, потому что в этом одном месте может быть перехвачено много интересного. Это также означает, что ваше приложение может иметь более одной версии протокола UIApplicationDelegate, а приведенный выше код может просто выбрать любую его реализацию, что вызовет некоторые серьезные проблемы.

Как Крис предложил в комментариях ниже, его гораздо более безопасный и производительный просто использовать [[UIApplication sharedApplication].delegate class]. который должен дать вам точную реализацию AppDelegate, известную приложению iOS, в момент вызова этой строки кода.

+1

Почему бы просто не использовать '[[UIApplication sharedApplication] .delegate class]'? – ChrisH

+1

@ChrisH, гораздо безопаснее и эффективнее использовать способ, которым вы поделились, я должен соответствующим образом обновить свой ответ. –