Как избежать случайного вызова на частные занятия UIKit?

Я только что столкнулся с очень странной проблемой. В моем текущем проекте я работаю со сложными представлениями и делаю некоторые модификации на лету.

Например, если view реагирует на setTextColor, тогда устанавливал новый цвет, используя следующий код

if ([view respondsToSelector:propertySelector]) {
    // Invoke method.
}

Случайно вызванный метод вернулся UIButtonLabel (который является частным скрытым
класс в UIKit), и выполнен вышеуказанным способом. В приведенном выше коде UIButtonLabel ответил наsetTextColor: но затем приложение вылетело в вызове.

Как избежать случайного доступа и вызова на UIKitчастные уроки?

2 ответа

Да, вы можете пройти цепочку обратных суперклассов, начиная с NSObject до вашего класса, проверяя, что ваш метод не является частью class_copyMethodList для проверяемого в данный момент класса и его метакласса (для методов класса). При этом убедитесь, что проверяемый в настоящее время класс не исходит от вашего [NSBundle mainBundle] ([NSBundle bundleForClass:]) как только это произойдет, вы можете прекратить поиск - вы достигли своего кода. Но, как вы можете себе представить, даже с кэшированием это очень медленный способ выполнения задач.

Возможно, вам лучше переделать свой код: попробуйте использовать conformsToProtocol: вместо respondsToSelector, Например, вы объявляете протокол

@protocol XYZSettableColor <NSObject>

@required
- (void)setSomethingWithColor:(UIColor *)textColor;

@end

Затем в вашем классе (классах) вы хотите объявить, что он соответствует протоколу (и, очевидно, реализовать необходимые методы)

@interface XYZMyControl : UIControl <XYZSettableColor>

@end

Позже, когда вы захотите убедиться, что переданный компонент квалифицирован для выполнения указанного метода:

- (void)applyTextColor:(UIColor *)color toControl:(id)control {
    if ([control conformsToProtocol:@protocol(XYZSettableColor)]) {
        [(id<XYZSettableColor>)control setSomethingWithColor:color];
    }
}

Я думаю, что нет никакой возможности на 100% проверить это. Вы должны знать, что target-c работает с вызовами методов, что означает, что нет никакого реального частного метода. (По крайней мере, любой может вызвать "приватные" методы).

Чтобы предотвратить вызов таких методов, вы должны избегать использования "executeSelector" и других методов вызова с селекторами, о которых вы еще не знаете.

Более того, существует гарантия в процессе отправки приложения. В конце процесса передачи, если вы использовали "рискованные" селекторы или вызовы методов с именами, которые Apple знает как "метод, используемый в частном API", появится предупреждение, сообщающее, где вы использовали частный API.

Таким образом, в конце все должно быть хорошо в конце процесса представления.

Другие вопросы по тегам