Apple заблокировала метод Swizzling в iOS 5?
Я немного поиграл и обнаружил, что приложение с методом Swizzling работает на iOS 4, но не на iOS 5.
ПРИМЕЧАНИЕ. Приложение работает на iOS 5, но не на части, когда используется метод Swizzling.
Apple заблокировала метод Swizzling в iOS 5?
Я немного поиграл и обнаружил, что приложение с методом Swizzling работает на iOS 4, но не на iOS 5.
ПРИМЕЧАНИЕ. Приложение работает на iOS 5, но не на части, когда используется метод Swizzling.
Apple отправила электронное письмо некоторое время назад некоторым разработчикам, которые, как было установлено, используют метод swizzling в приложениях App Store:
Ваше приложение, xxx, в настоящее время отправленное в App Store, использует method_exchangeImplementations для обмена реализацией Apple предоставили API с вашими собственными реализациями. Из-за предстоящих изменения, это поведение в вашей заявке может вызвать сбой или вызвать потеря пользовательских данных на iPhone OS 4.0.
xxx использует метод_exchangeImplementations для обмена реализацией dealloc с вашим методом ttdealloc. Он также реализация метода popViewControllerAnimated: с помощью метод popViewControllerAnimated2:.
Пожалуйста, немедленно устраните эту проблему и загрузите новый iTunes Connect. Мы можем удалить вашу заявку, если считаем, что делать это разумно или необходимо.
Похоже, они хотели избавиться от него, поэтому я бы сказал, что шансы довольно высоки, и теперь они полностью заблокировали его.
UPDATE: (Мое приложение использует этот метод и находится в appstore)
Метод swizzling, похоже, работает с 30 мая 2012 года. Это моя реализация.
(Это для тех из вас, кто оглядывается и находит плохой код на страницах вики и просто хочет быстро реализовать.)
Swizz.h
#import <Foundation/Foundation.h>
void ActivateAutoSwizz();
void Swizz(Class c, SEL orig, SEL replace);
@interface NSObject (swizz)
// This Method allows the class to Swizzle more methods within itself.
// And allows for an overridable init method in Class Extensions
// ######################
// //// To Swizzle a method, call Swizzle once on the class in question.
// //// dispatch_once is a good way to handle that.
// static dispatch_once_t onceToken;
// dispatch_once(&onceToken, ^{
// Swizz([UITableViewCell class], @selector(reuseIdentifier), @selector(classReuseIdentifier));
// });
- (void) swizzInit;
@end
Swizz.m
#import "Swizz.h"
#import <objc/runtime.h>
#import <objc/message.h>
//....
void Swizz(Class c, SEL orig, SEL replace)
{
Method origMethod = class_getInstanceMethod(c, orig);
Method newMethod = class_getInstanceMethod(c, replace);
if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
class_replaceMethod(c, replace, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
else
method_exchangeImplementations(origMethod, newMethod);
}
@implementation NSObject (swizz)
// Load gets called on every object that has it. Off Thread, before application start.
+ (void) load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Swizz([NSObject class], @selector(init), @selector(initIntercept));
});
}
- (id) initIntercept{
self = [self initIntercept]; // Calls the Original init method
if(self){
[self swizzInit];
}
return self;
}
- (void) swizzInit{
//Do Nothing.. Gives an extension point for other classes.
}
@end
Я построил это, чтобы позволить мне перехватить идентификатор повторного использования в UITableViewCell с расширением UITableViewCell.
Вот этот пример.
UITableViewCell + ReuseIdentifier.h
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
@interface UITableViewCell (ReuseIdentifier)
@end
UITableViewCell + ReuseIdentifier.m
#import "UITableViewCell+ReuseIdentifier.h"
#import "Swizz.h"
@implementation UITableViewCell(ReuseIdentifier)
// Edited to remove Class variable.
// Class variables in Categories are Global.
// And as it turns out, this method did not need the variable anyhow.
- (NSString *)classReuseIdentifier{
NSString *reuseIdentifierResult = [self classReuseIdentifier]; // Gets the original reuseIdentifier
if (reuseIdentifierResult == nil){
reuseIdentifierResult = [[self class] description];
}
return reuseIdentifierResult;
}
// Alternatively you can use the +(void)load method on the class to achieve the same thing.
- (void)swizzInit{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Swizz([UITableViewCell class], @selector(reuseIdentifier), @selector(classReuseIdentifier));
});
}
@end
Как вы можете видеть, ActivateAutoSwizz(), а также мой метод swizzInit используют dispatch_once для выполнения swizzle один раз.
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Swizz([NSObject class], @selector(init), @selector(initIntercept));
});
Если вы выполните его дважды. он меняет ваш метод обратно на оригинал. Надеюсь, это поможет некоторым из вас разработчиков iOS.
ПРИМЕЧАНИЕ. Я определил, что загрузка + (void) вызывается один раз при запуске приложения и является прекрасным местом для достижения метода swizzle. К сожалению, в некоторых ситуациях dev + (void) загрузка не вызывается, вы можете протестировать свое приложение, чтобы убедиться, что эти методы вызывают.
Хорошо, мы получили OK о mont hago (начало мая 2012 года) для приложения, которое сильно использовало метод Swizzling для настройки стандартных компонентов пользовательского интерфейса в iOS4 (iOS5 с использованием внешнего вида). Кроме того, метод swizzling - полностью документированный API, который также предоставляет очень мощные функции, не связанные с самим Apple или использованием частных API. Мне трудно поверить, что они могут отказаться от такой вещи!
В любом случае, пожалуйста, сообщите всем, если вы увидите больше отклонений, связанных с этим! Спасибо!