【问题标题】:Calling a method from another 'm' file从另一个“m”文件调用方法
【发布时间】:2012-10-31 00:23:54
【问题描述】:

我的应用程序的大部分代码都在一个名为 MyViewController 的“m”文件中。该应用程序实现了一个包含 UIWebView 对象的自定义 UIView。 UIView 和 UIWebView 的代码保存在名为 CustomUIView 的单独“m”文件中。

我已经设法使用委托覆盖了对 UIWebView 对象中的 URL 超链接的点击。但是,我想让这些点击启动存储在我的主应用程序代码中的方法。此方法称为“popupView”,并采用单个参数“inputArgument”。 inputArgument 是用户单击的 URL 的文本。事实上,这个方法和我的自定义 UIView 启动的方法是一样的。

无论如何,我想要做的是让我覆盖的 URL 点击导致 popupView 方法启动,从而导致另一个 UIView 在被点击的那个之上打开。

问题是检测到 URL 点击的 'm' 文件看不到 'popupView' 方法,因为它包含在 MyViewController 'm' 文件中。如何从另一个“m”文件中调用 popupView 方法?

【问题讨论】:

    标签: objective-c


    【解决方案1】:

    直接

    1. MyViewController.h中声明MyViewController的方法-popupView:
    2. #importMyViewController.hCustomUIView.m
    3. CustomUIView 提供对MyViewController 的[one] 实例的引用,例如通过CustomUIView.h 中声明的@property

    对于(1)MyViewController(在MyViewController.h 中)的@interface 应该有点像这样

    @interface MyViewController : UIViewController
    {
        //....
    }
    - (void)popupView:(NSString *)urlText;
    //....
    @end
    

    对于(2)UIViewController.m 应该在顶部附近的某处有以下内容

    #import "CustomUIView.h"
    #import "MyViewController.h"
    

    对于(3)CustomUIView.h 中的@interface 应该类似于

    @interface CustomUIView : UIView
    {
        //....
    }
    @property (nonatomic, weak) MyViewController *viewController;
    @end
    

    这个属性需要在MyViewController 拥有的CustomUIView 实例创建后的一段时间内设置。如果您的CustomUIViewMyViewController.xib 中,则可以通过将关键字IBOutlet 添加到属性声明中来设置此属性,如下所示

    @property (nonatomic, weak) IBOutlet MyViewController *viewController;
    

    并将此属性指向XIB 中的“文件所有者”。相反,如果您以编程方式创建 CustomUIView,则可以在初始化后立即在其上设置此属性。

    委托

    然而,这远非最佳实践。使用delegate pattern 会更好。为此,您需要

    1. 定义一个委托protocol
    2. 将“代表”@property 添加到 CustomUIView
    3. 在适当的时候调用委托对象的委托方法。
    4. MyViewController中实现协议。
    5. MyViewController实例所拥有的CustomUIView实例的“委托”@property设置为MyViewController实例。

    让我们将委托协议称为富有想象力的东西,例如CustomUIViewDelegate。对于(1),我们将在CustomUIView.h 的顶部声明如下:

    @class CustomUIView;
    
    @protocol CustomUIViewDelegate <NSObject>
    - (void)customUIView:(CustomUIView *)customView didSelectURLText:(NSString *)urlText;
    @end
    

    请注意,我们必须 forward declare 我们的类 CustomUIView 以便编译器能够理解协议方法 customUIView:didSelectURLText: 中第一个参数的类型。

    对于(2),我们将执行与上面的(3) 非常相似的操作:您的CustomUIView @interface 看起来像

    @interface CustomUIView : UIView
    {
        //....
    }
    @property (nonatomic, weak) id<CustomUIViewDelegate> *delegate;
    @end
    

    同样,如果我们要在 Interface Builder 中设置此属性,我们需要使用 IBOutlet 关键字向 IB 宣布它:

    @property (nonatomic, weak) IBOutlet id<CustomUIViewDelegate> *delegate;
    

    对于(3),我们需要在适当的时候在我们的委托对象self.delegate上调用委托方法customUIView:didSelectURLText:

    在你的问题中,你写道

    我已经设法使用委托覆盖了对 UIWebView 对象中的 URL 超链接的点击。

    那么,假设CustomUIView 有一个实例方法

    - (void)didSelectURL:(NSURL *)url
    {
        //....
    }
    

    当用户在 UIWebView 中选择一个链接时,调用了哪个。 CustomUIView 的代表需要知道这一点:

    - (void)didSelectURL:(NSURL *)url
    {
        //...
        if ([self.delegate respondsToSelector:@selector(customUIView:didSelectURLText:)]) {
        {
            [self.delegate customUIView:self didSelectURLText:url.absoluteString];
        }
    }
    

    请注意,我们首先检查 CustomUIView 实例的委托对象是否通过调用 respondsToSelector: 来实现感兴趣的选择器 (customUIView:didSelectURLText:)。

    对于(4),我们需要首先&lt;CustomUIViewDelegate&gt; 添加到MyViewController@interface 声明中,并确保将#import CustomUIView.h 添加到我们所在的文件中使用符号CustomUIViewDelegate。我们的MyViewController@interface 看起来像这样:

    #import "CustomUIView.h"
    
    @interface MyViewController : UIViewController <CustomUIViewDelegate>
    {
        //....
    }
    //....
    @end
    

    更重要的是,我们需要在MyViewController@implementation实现CustomUIViewDelegate协议;到目前为止,我们只声明 MyViewController 采用它。

    为此,由于我们的协议仅包含一种方法,因此我们只需要添加自己的 -customUIView:didSelectURLText: 实现即可。我们的MyViewController@implementation 看起来像这样:

    #import "MyViewController.h"
    
    @implementation MyViewController
    
    //....
    
    - (void)popupView:(NSString *)urlText
    {
        //....
    }
    
    #pragma mark - CustomUIViewDelegate
    
    - (void)customUIView:(CustomUIView *)customView didSelectURLText:(NSString *)urlText
    {
        [self popupView:urlText];
    }
    
    //....
    
    @end
    

    最后,对于(5),我们需要设置MyViewController 实例拥有的CustomUIView 实例的delegate 属性。我对MyViewController 与其CustomUIView 实例的关系知之甚少,无法明确描述如何执行此操作,但我将提供一个示例:我假设您以编程方式在-[MyViewController loadView] 添加CustomUIView 作为MyViewController 视图的子视图。所以你对-loadView 的实现看起来有点像这样:

    - (void)loadView
    {
        [super loadView];
        
        //....
        
        CustomUIView *customView = //....        
        //....
        [self.view addSubview:customView];
        
        //....
        
    }
    

    此时剩下要做的就是将局部变量customViewdelegate@property设置为self

    customView.delegate = self;
    

    编辑:根据有关CustomUIViewMyViewController 之间关系的新信息进行了更新 (5)。

    在您的评论中,您写道您的CustomUIView 被添加为cvc.view 的子视图,其中cvcCustomUIView 的方法-[CustomUIView show]CustomUIViewController 的一个实例。因此,您注意到写customView.delegate = self; 与写self.delegate = self 相同,这显然不是您想要做的。

    您希望将CustomUIViewdelegate 属性设置为MyViewController 的实例。因此,您的方法 -[CustomUIView show] 应该类似于

    - (void)show
    {
        //....
        [cvc.view addSubview:self];
    
        self.delegate = mvc;
    }
    

    其中mvcMyViewController 的实例。

    【讨论】:

    • 谢谢,这是一个真正全面的答案,它教会了我很多关于委派的知识。我讨厌要求对如此完整的回应进行跟进,但我想我只是在最后一步挣扎。我的 CustomUIView 被添加到方法 '- (void) show' 中,创建子视图的行是 '[cvc.view addSubview: self];' (cvc 是一个 CustomUIViewController*)。这一切都是作为 CustomUIView 实现中的一个方法发生的。因此,我无法添加“customView.delegate = self;”行,因为它变成了“self.delegate = self;”。也许,我错误地调用了该方法...'[didSelectTerm term];'?
    • @CaptainProg 查看我的编辑:我添加了(3) 并修改了(5) 以考虑这些新信息。查看对(5) 的修订后,您可能想知道如何在-[CustomUIView show] 中获得指向MyViewController 实例的指针。我对您的程序结构知之甚少,无法最终解决这个问题。我这样做了,我需要知道谁拥有和创建CustomUIViewController 的实例以及谁拥有和创建CustomUIView 的实例。
    【解决方案2】:

    好吧,既然您正在编写 CustomUIView,为什么不实现像 initWithPopupDelegate:(MyViewController *)delegate 这样的构造函数,并以这种方式在实例变量中保留对 MyViewController 实例的引用,然后调用该方法。

    (在CustomUIView.h 的顶部添加@class MyViewController;,在CustomUIView.m 的顶部添加#import "MyViewController.h",以便编译器知道您正在使用的类。)

    或者,如果只有一个MyViewController 实例,您可以为MyViewController 定义一个类方法,例如+ (MyViewController *)instance,并让它返回对一个实例的引用(您将其存储在一个类中变量并在您第一次创建实例时设置,请参阅“单例模式”)。但在不知道代码细节的情况下,我建议第一个解决方案(委托)更简单、更灵活。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多