Как избежать случайного вызова на частные занятия 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.
Таким образом, в конце все должно быть хорошо в конце процесса представления.