Objective-C 前向调用:

发布于 2024-11-18 20:29:11 字数 903 浏览 3 评论 0原文

我经常做这样的事情:

CoolViewController *coolViewController = [[CoolViewController alloc] init];
[self.navigationController pushViewController:coolViewController animated:YES];
[coolViewController release];

UINavigationController 的类别中,我如何重写 forwardInitation: 这样我就可以这样做:

[self.navigationController pushCoolViewControllerAnimated:YES];
  1. 请在中包含相关代码您的答案,而不仅仅是解释。谢谢!

  2. 请随意评论这是否是一个好的做法。我也是出于教育目的而提出这个问题,但在我看来,在这种情况下,代码的简化可能会超过处理时间和处理过程中不明显的(正确的?)成本。内存使用情况。另外,我有 Ruby 背景,喜欢使用动态编程来简化事情,例如 Rails 中的动态查找器(例如 find_by_name)。

  3. 如果您可以实现 pushCoolViewControllerAnimated:withBlock 并在初始化视图控制器后调用该块,则将获得奖励积分,从而允许我在创建的视图控制器上设置某些实例变量。

更新:我刚刚记得 ARC 即将推出。因此,这个特定的示例可能没有那么有用,但仍然是一个很好的练习/示例,可以在其他情况下使用,例如,核心数据和动态查找器。传递一个块来配置NSFetchRequest

I often do something like:

CoolViewController *coolViewController = [[CoolViewController alloc] init];
[self.navigationController pushViewController:coolViewController animated:YES];
[coolViewController release];

How would I, in a category of UINavigationController, override forwardInvocation: so that I could just instead do:

[self.navigationController pushCoolViewControllerAnimated:YES];
  1. Please include the relevant code in your answer, not just an explanation. Thank you!

  2. Feel free to comment on whether this is good practice. I'm also asking this for educational purposes, but it seems to me that in this case, the simplification in code may outweight the unnoticeable (correct?) cost in processing time & memory usage. Also, I come from a Ruby background and love to use dynamic programming to simplify things, e.g., dynamic finders (e.g., find_by_name) in Rails.

  3. Bonus points if you could implement pushCoolViewControllerAnimated:withBlock and invoke the block after initializing the view controller, allowing me to set certain instance variables on the view controller created.

UPDATE: I just remembered that ARC is coming soon. So this specific example may not be so helpful then, but still a great exercise/example that could be used in other cases, e.g., dynamic finders for Core Data & passing a block to configure the NSFetchRequest.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

○愚か者の日 2024-11-25 20:29:11

使用《Objective-C 运行时编程指南》中描述的动态方法解析机制,具体为 +[NSObjectresolveInstanceMethod:]

@implementation UINavigationController (FWD)
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    NSString *name = NSStringFromSelector(sel);
    NSString *prefix = @"push";
    NSString *suffix = @"Animated:";
    if ([name hasPrefix:prefix] && [name hasSuffix:suffix]) {
        NSRange classNameRange = {[prefix length],
            [name length] - [prefix length] - [suffix length]}
        NSString *className = [name substringWithRange:classNameRange];
        Class cls = NSClassFromString(className);
        if (cls) {
            IMP imp = imp_implementationWithBlock(
            ^(id me, BOOL animated) {
                id vc = [[cls alloc] init];
                [me pushViewController:vc animated:animated];
                [vc release];
            });
            class_addMethod(cls, sel, imp, "v@:c");
            return YES;
        }
    }
    return [super resolveInstanceMethod:sel];
}
@end

当然,如果 UINavigationController 已经使用 + resolveInstanceMethod:,你现在已经破坏了它。在 UINavigationController 的子类中执行此操作,或者使用方法调配来调用原始实现,可以解决该问题。

接受创建后块的版本是一个简单的扩展(更改块参数,更改类型编码,更改选择器名称模式以及如何提取预期的类名称)。

Use the dynamic method resolution mechanism described in the Objective-C Runtime Programming Guide, specifically, +[NSObject resolveInstanceMethod:]:

@implementation UINavigationController (FWD)
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    NSString *name = NSStringFromSelector(sel);
    NSString *prefix = @"push";
    NSString *suffix = @"Animated:";
    if ([name hasPrefix:prefix] && [name hasSuffix:suffix]) {
        NSRange classNameRange = {[prefix length],
            [name length] - [prefix length] - [suffix length]}
        NSString *className = [name substringWithRange:classNameRange];
        Class cls = NSClassFromString(className);
        if (cls) {
            IMP imp = imp_implementationWithBlock(
            ^(id me, BOOL animated) {
                id vc = [[cls alloc] init];
                [me pushViewController:vc animated:animated];
                [vc release];
            });
            class_addMethod(cls, sel, imp, "v@:c");
            return YES;
        }
    }
    return [super resolveInstanceMethod:sel];
}
@end

Of course, if UINavigationController already uses +resolveInstanceMethod:, you've now broken it. Doing this in a subclass of UINavigationController, or using method swizzling to enable invoking the original implementation, would solve that problem.

The version accepting a post-creation block is a straightforward extension (change the block parameters, change the type encoding, change the selector name pattern and how you extract the intended class name).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文