方法Swizzling在iOS 5?

苹果在iOS 5中阻止方法Swizzling?

我在做一个小游戏,发现Method Swizzling的应用程序可以在iOS 4上运行,但在iOS 5上却不能运行。

注:该应用程序在iOS 5上工作,但不使用Method Swizzling时该部分。

苹果前一段时间发送了一封电子邮件给一些被发现在App Store应用中使用方法debugging的开发者:

当前发布到App Store的您的应用程序xxx正在使用method_exchangeImplementations将Apple提供的API的实现与您自己的实现交换。 由于即将发生的变化,您的应用程序中的这种行为可能会导致崩溃或iPhone OS 4.0上的用户数据丢失。

xxx使用method_exchangeImplementations与你的方法ttdealloc交换dealloc的实现。 它还交换popViewControllerAnimated方法的实现:用你的方法popViewControllerAnimated2 :.

请立即解决此问题,并将新的二进制file upload到iTunes Connect。 如果我们认为这样做是谨慎或必要的,我们可能会删除您的申请。

看起来他们想摆脱它,所以我认为现在已经完全阻止了它的可能性非常高。

更新 :(我的应用程序使用此方法,并在appstore中)

2012年5月30日,方法调整似乎工作。这是我的实施。

(这是对于你四处寻找,并在维基页面上find不好的代码,只是想快速实现。)

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 

我build立了这个允许我在UITableViewCell扩展中拦截UITableViewCell上的reuseIdentifier。

这是这个例子。

的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)加载,并且是实现方法debugging的绝佳地点。 不幸的是,在某些开发环境中,不会调用+(void)加载,您可能需要testing您的应用程序以确保调用这些方法。

那么,我们收到了关于mont hago(2012年5月开始)的一个确定,这个应用程序使用了很多Swizzling方法来自定义iOS4中的标准UI组件(使用外观的iOS5)。 此外,方法swizzling是一个完全logging的API,也提供了非常强大的function,不涉及苹果本身或使用私有API。 我觉得很难相信他们会拒绝这样的事情!

无论如何,请告诉大家,如果你看到更多有关这个拒绝! 谢谢!