方法在ios5中进行搅拌



苹果是否在iOS 5中阻止了Method swizling ?

我玩了一下,发现一个带有Method Swizzling的应用程序可以在iOS 4上运行,但不能在iOS 5上运行。

苹果不久前向一些被发现在App Store应用程序中使用方法swizling的开发者发送了一封电子邮件:

你的应用程序,xxx,当前发布到应用程序商店正在使用method_exchangeImplementations交换Apple的实现提供带有您自己实现的api。因为即将到来更改时,此行为可能会导致应用程序崩溃或导致iPhone OS 4.0的用户数据丢失。

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

请立即解决此问题并将新的二进制文件上传到iTunes连接。如果我们相信这一点,我们可能会删除你的申请这样做是谨慎的或必要的。

看起来他们想要摆脱它,所以我认为他们现在很有可能已经完全封锁了它。

UPDATE:(我的应用程序使用此方法并且在appstore中)

方法混合似乎在2012年5月30日起起作用。这是我的实现

(这是为那些你四处寻找,发现wiki页面上的坏代码,只是想要一个快速实现。)

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上的reuseIdentifier与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) load在应用程序启动时被调用一次,这是实现方法swizzle的好地方。不幸的是,在一些开发情况下+(void)load没有被调用,你可能需要测试你的应用程序,以确保这些方法被调用

我们在一个月前(2012年5月初)收到了一款应用的批准,该应用大量使用Swizzling方法来定制iOS4中的标准UI组件(iOS5使用外观)。此外,method swizzling是一个完全文档化的API,它还提供了与Apple本身或使用私有API无关的非常强大的功能。我很难相信他们会拒绝这样的事情!

无论如何,如果你看到更多与此相关的拒绝,请通知每个人!谢谢!

最新更新