苹果是否在iOS 5中阻止了方法交换(Method Swizzling)?
我进行了一些尝试,发现一个使用方法交换的应用程序可以在iOS 4上运行但不能在iOS 5上运行。
注意:该应用程序在iOS 5上可以正常运行,但在使用方法交换时无法运行。
苹果是否在iOS 5中阻止了方法交换(Method Swizzling)?
我进行了一些尝试,发现一个使用方法交换的应用程序可以在iOS 4上运行但不能在iOS 5上运行。
注意:该应用程序在iOS 5上可以正常运行,但在使用方法交换时无法运行。
苹果曾向一些在App Store应用中使用方法交换技术的开发人员发送了一封电子邮件:
你的应用程序xxx目前已发布到App Store,正在使用method_exchangeImplementations来交换Apple提供的API实现和你自己的实现。由于即将到来的更改,你的应用程序中的这种行为可能会导致iPhone OS 4.0上的崩溃或导致用户数据丢失。
xxx使用method_exchangeImplementations来交换dealloc方法的实现和你的ttdealloc方法。它还将popViewControllerAnimated:方法的实现与你的popViewControllerAnimated2:方法进行了交换。
请立即解决此问题并将新二进制文件上传至iTunes Connect。如果我们认为这样做是明智或必要的,我们可能会删除你的应用程序。
看起来他们想要摆脱它,因此我可以说它完全被封锁的可能性非常高。
class_addMethod
在运行时添加额外的属性。class_addIvar
在objc_registerClassPair
之后停止工作,所以您无法再使用它了,遗憾。 - Tommyobjc_setAssociatedObject
、objc_getAssociatedObject
和 objc_removeAssociatedObjects
。运行时可以在低级别上将一个对象链接到另一个对象,然后您可以编写 setter 和 getter 来弥补差距。有关前者,请参见 http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocAssociativeReferences.html。 - Tommy更新:(我的应用程序使用此方法并在App Store中)
截至2012年5月30日,方法交换似乎已经起作用了。这是我的实现。
(这是为那些四处寻找错误代码的维基页面并只想要快速实现的人准备的。)
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
#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来执行一次交换。
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Swizz([NSObject class], @selector(init), @selector(initIntercept));
});
如果你执行两次,它会将你的方法转换回原始状态。希望这对一些iOS开发者有所帮助。
注意:我已经确定+(void)load在应用程序启动时只被调用一次,并且是一个非常好的地方来实现方法交换。不幸的是,在某些开发情况下,+(void)load可能不会被调用,你可能需要测试你的应用程序以确保这些方法被调用。
好的,我们大约一个月前(2012年5月初)收到了关于一个应用程序的批准,该应用程序大量使用方法交换来自定义iOS4中的标准UI组件(iOS5使用外观)。此外,方法交换是一个完全记录的API,还提供了与苹果本身或私有API无关的非常强大的功能。我很难相信他们会拒绝这样的东西!
无论如何,请在看到更多与此相关的拒绝时保持每个人都知情!谢谢!