Método Swizzling en iOS 5?

¿Apple bloqueó el método Swizzling en iOS 5?

Estuve jugando un poco y descubrí que una aplicación con Method Swizzling funciona en iOS 4 pero no en iOS 5.

NOTA: la aplicación funciona en iOS 5 pero no en la parte cuando se usa Method Swizzling.

Apple envió un correo electrónico hace un tiempo a algunos desarrolladores que se descubrió que usaban el método swizzling en las aplicaciones de la App Store:

Su aplicación, xxx, actualmente publicada en App Store está utilizando method_exchangeImplementations para intercambiar la implementación de las API proporcionadas por Apple con sus propias implementaciones. Debido a los próximos cambios, este comportamiento en su aplicación puede causar un locking o causar la pérdida de datos del usuario en iPhone OS 4.0.

xxx usa method_exchangeImplementations para intercambiar la implementación de dealloc con su método ttdealloc. También intercambia la implementación del método popViewControllerAnimated: con su método popViewControllerAnimated2 :.

Resuelve este problema de inmediato y sube tu nuevo binario a iTunes Connect. Podemos eliminar su solicitud si creemos que hacerlo es prudente o necesario.

Parece que querían deshacerse de él, así que yo diría que hay muchas posibilidades de que lo hayan bloqueado por completo.

ACTUALIZAR : (Mi aplicación usa este método y está en la tienda de aplicaciones)

El Swizzling del método parece estar funcionando desde el 30 de mayo de 2012. Esta es mi implementación.

(Esto es para aquellos de ustedes que miran a su alrededor y encuentran un código incorrecto en las páginas wiki y solo quieren una implementación rápida).

Swizz.h

 #import  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  #import  //.... 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 

Construí esto para permitirme interceptar el reuseIdentifier en la UITableViewCell con una extensión UITableViewCell.

Aquí está ese ejemplo.

UITableViewCell + ReuseIdentifier.h

 #import  #import  @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 

Como puede ver, tanto ActivateAutoSwizz () como mi método swizzInit usan dispatch_once para ejecutar el swizzle una vez.

 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Swizz([NSObject class], @selector(init), @selector(initIntercept)); }); 

Si lo ejecutas dos veces. invierte su método vuelva a cambiar al original. Espero que esto ayude a algunos de ustedes desarrolladores de iOS por ahí.

NOTA: He determinado que la carga + (nula) se llama una vez al inicio de la aplicación y es un lugar maravilloso para lograr el método Swizzle. Lamentablemente, en algunas situaciones de desarrollo, no se llama a la carga (nula), es posible que desee probar su aplicación para asegurarse de que se están llamando a estos métodos.

Bien, recibimos el OK sobre un mont hago (principio de mayo de 2012) para una aplicación que hizo un gran uso del método Swizzling para personalizar los componentes UI estándar en iOS4 (iOS5 con apariencia). Además, el Swizzling de métodos es una API totalmente documentada que también proporciona funciones muy potentes que no están relacionadas con Apple ni con el uso de API privadas. ¡Me cuesta creer que puedan rechazar tal cosa!

De todos modos, por favor, mantén a todos informados si ves más rechazos relacionados con esto. ¡Gracias!