gpt4 book ai didi

iphone - 是否可以在 Objective-C 中重定向系统 API?

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:26:20 26 4
gpt4 key购买 nike

由于某些原因,我不得不保留原始代码而不做任何修改,而是尝试将系统 API 重定向到我的代码中,然后再回调到原始代码。例如,我想在 [NSString stringWithFormat:] 中做更多的事情。

现在我尝试使用 method swizzling。但是似乎 NSString 在 main 运行时没有加载,我将 swizzling 方法移动到 MyAppDelegate。之后 class_getInstanceMethod([NSString class], @selector(stringWithFormat:)) 不为零。但是,swizzling 方法仍然无效,因为 class_getInstanceMethod([NSString class], @selector(override_stringWithFormat:)) 仍然是 nil,我该如何解决?

谢谢,俱乐部

@interface NSString (MyNSString)

+ (id)stringWithFormat:(NSString *)format, ...;
@end


@implementation NSString (MyNSString)
+ (id)stringWithFormat:(NSString *)format, ... {
//do something...
[NSString stringWithFormat:format];
}
@end

这是MyAppDelegate中的代码

#import "MyNSString.h"
-(void) MethodSwizzle:(Class)c replaceOrig:(SEL) origSEL withNew:(SEL) overrideSEL {
Method origMethod = class_getInstanceMethod(c, origSEL);
Method overrideMethod = class_getInstanceMethod(c, overrideSEL);

if(class_addMethod(c, origSEL, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod)))
class_replaceMethod(c, overrideSEL, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
else
method_exchangeImplementations(origMethod, overrideMethod);
}

- (BOOL) application:(UIApplication*) application didFinishLaunchingWithOptions:(NSDictionary *) options {
...
//Unit test
NSString *a=[NSString override_stringWithFormat:@"Test"]; //returned something
Method b = class_getInstanceMethod([NSString class], @selector(override_stringWithFormat:)); //return nil;

//do something...
[self MethodSwizzle:[NSString class] replaceOrig:@selector(stringWithFormat:) withNew:@selector(override_stringWithFormat:)];

}

最佳答案

不确定您要做什么,问题有点不清楚。另外,不要试图从 NSString 继承,它是类簇的一部分,所以它比只覆盖一个方法要复杂得多。你甚至必须 mplement the storage yourself .变得非常复杂。

有两种方法可以在 Objective-C 中向现有类添加方法:Categoriesmethod Swizzling .

类别允许您在现有类上定义新方法,您不能可靠地使用类别替换方法。例如:

@interface NSString (MyStuff)
- (id)mySpecialInit;
@end;

@implementation NSString (MyStuff)
/* implementation of -(id)mySpecialInit would go here */
@end

同样,此方法不会可靠地替换类中的现有方法。

为此,您需要方法调配。警告 - 这是运行时的一项高级功能,很容易让自己陷入调试噩梦,因此请谨慎使用。 Swizzling 允许您用具有相同签名的另一种方法替换一种方法的实现。使用一些技巧,您也可以调用 super 实现。 Matt Gallagher 通常被认为拥有 best implementation of method swizzling ,因为它允许可靠地调用预先存在的实现(称为后续实现)。查看有关 Cocoa with Love 的链接文章,了解示例用法。您编辑的代码可能不起作用,因为您正在尝试调配类方法,但使用的是 getInstanceMethod 函数。请改用 class_getClassMethod() 。此外,您需要重命名您的类别 stringWithFormat 方法,它不得与真正的方法名称冲突。最后一个警告——我从未见过在带有可变参数 (...) 和 this C q&a 的方法上使用方法调配。让我相信这是不可能的(尝试 this post 作为可能的解决方案)。作为一项学术练习,下面是它可能的样子:

NSString+MyMethods.h

@interface NSString (MyMethods) 
+ (id)clu_stringWithFormat:(NSString *)format,...;
@end

NSString+MyMethods.m:

@implementation NSString (MyMethods) 
+ (id)clu_stringWithFormat:(NSString *)format,... {
//Do your stuff here
//call supersequent implementation
//again, I have no idea if this will work as is, you might need to tweak how it passes the variable argument list
invokeSupersequent(format);
}

+(void)load {
//do your method swizzle in here, this is called one time only
Method origMethod = class_getClassMethod([NSString class], @selector(stringWithFormat:);
Method replMethod = class_getClassMethod([NSString class], @selector(clu_stringWithFormat:);

method_exchangeImplementations(origMethod, replMethod);
}

鉴于这可能是不可能的,否则是一个非常糟糕的主意 - 您正在更改类集群中特定类的操作方式,Apple 表示“不要这样做”。并且有充分的理由 - 如果有人调用 [NSMutableString stringWithFormat:] 或分配一个 NSString 然后调用 -initWithFormat: 会发生什么?创建具有某种格式的字符串有很多有效的路径,你将有一段痛苦的时间试图维护拦截所有这些的代码。我鼓励您重新考虑它的设计——无论您试图解决什么问题,都可能有一种更简单、更易于维护的方法来实现它。例如,添加您自己的字符串工厂。

关于iphone - 是否可以在 Objective-C 中重定向系统 API?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6462907/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com