【问题标题】:How to use @protocol in AppDelegate iPhone app?如何在 AppDelegate iPhone 应用程序中使用@protocol?
【发布时间】:2012-08-17 12:23:17
【问题描述】:

我正在使用 5 个屏幕的 iPhone 应用程序。我想刷新 UITabBarController 中第 4 个屏幕中的值。我在 AppDelegate 中添加了@protocol,但它没有调用。这是我第一次使用@protocol,请您帮我解决这个问题,

AppDelegate.h

@protocol ReloadViewControllerDelegate <NSObject>

-(void) refreshViewController:(NSString *)result;

@end

id refreshViewControllerDelegate;

@property (nonatomic, retain) id refreshViewControllerDelegate;

我已经合成了。

AppDelegare.m

@synthesize refreshViewControllerDelegate;

if ([refreshViewControllerDelegate conformsToProtocol:@protocol(ReloadViewControllerDelegate)]) 
{
   [refreshViewControllerDelegate performSelectorOnMainThread:@selector(refreshViewController:) withObject:@"YES" waitUntilDone:NO];                
}// Control not come inside of if Condition.... From here i want to update the fourthViewController..

但是control not go inside of the if condition。你能指导我哪里做错了吗?

在我的第四个 ViewController.h

#import "AppDelegate"

@interface fourthViewController : UIViewController <ReloadViewControllerDelegate>

在我的第四个 ViewController.m

-(void) refreshViewController:(NSString *)result
{
    NSLog(@"Result : %@", result);
}

谁能帮我做这件事?提前致谢。

【问题讨论】:

  • refreshViewControllerDelegate 是否设置为您的 fourthViewController 实例?
  • 您确定refreshViewControllerDelegate 不是nil
  • 对不起朋友们。如果您不介意,我无法理解您能否纠正我的问题。这对我有帮助吗?谢谢。
  • @Gopinath 你在哪里设置reloadChatViewControllerDelegate 到你的第四个视图控制器?
  • @Jilouc 谢谢。我已经编辑了名称。

标签: iphone objective-c ios xcode4.2 protocols


【解决方案1】:

你需要像这样声明你的委托:

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

id 会起作用,但是通过使用 ,您可以确保您分配的委托实际上正在实现协议,您可能仍然需要确保它响应选择器,但前提是声明了某些方法作为

@optional

确保你合成它,最重要的是确保你设置它,它不是 nil。

【讨论】:

  • 我已经尝试过您的代码,但它显示了我在问题中提到的警告。请你帮助我好吗?我已经合成了 reloadChatViewControllerDelegate。我不知道如何检查它是否为空。请帮我。谢谢
  • 编译器无法知道 id 实际上是从 NSObject 继承的,这是声明该方法的地方,您有 2 个选项,而不是将委托声明为 id,只需将其声明为 NSObject,或将其转换为 ( NSObject *) 然后调用方法。
  • @Gopinath 要消除警告,请像 @property (nonatomic, weak) IBOutlet NSObject&lt;ReloadViewControllerDelegate&gt; *delegate; 一样声明委托或使用强制转换 [(NSObject *)refreshViewControllerDelegate performSelectorOnMainThread:@selector(refreshViewController:) withObject:@"YES" waitUntilDone:NO];
  • @Jilouc 感谢您的回复。我会尝试你的代码并让你知道。再次感谢。
  • 我已经尝试了你的想法,但是控件仍然没有进入 if 条件。我的代码是,id reloadChatViewControllerDelegate;和@property(非原子,弱)IBOutlet NSObject *reloadChatViewControllerDelegate;。请帮我。谢谢..
【解决方案2】:

您收到警告是因为您将代理输入为idid 是泛型类型,这意味着编译器不知道哪些方法或属性可能可用。为了消除您的警告,请将您的委托声明为 NSObject:

@property (nonatomic, retain) NSObject <ReloadViewControllerDelegate> *refreshViewControllerDelegate;

通过声明为 NSObject,编译器现在知道 NSObject 拥有的所有方法,然后您可以调用:

-performSelectorOnMainThread:withObject:waitUntilDone:

在您的委托上没有警告。祝你好运!

【讨论】:

  • 感谢您的回复。我已经尝试过你上面提到的这个。但是控件没有进入AppDelegate.m下面代码中的if条件, if ([refreshViewControllerDelegate conformsToProtocol:@protocol(ReloadViewControllerDelegate)]) { [refreshViewControllerDelegate performSelectorOnMainThread:@selector(refreshViewController:) withObject:@"YES" waitUntilDone:NO] ; }。请帮我。谢谢。
  • 而不是conformsToProtocol,你试过用respondsToSelector:吗?
  • 仍然控制不进入if条件。
  • 那么您的控制器一定没有正确采用协议,或者您没有将委托设置为已实现协议的类。
【解决方案3】:

试试这个:

@protocol ReloadViewControllerDelegate <NSObject>

-(void) refreshViewController:(NSString *)result;

@end

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (weak) id <ReloadViewControllerDelegate>refreshViewControllerDelegate;
@end

在 AppDelegate.m 中

@implementation AppDelegate
@synthesize window, refreshViewControllerDelegate;

...

这里的 Tab4ViewController 是类的名称。

    if ([Tab4ViewController conformsToProtocol:@protocol(ReloadViewControllerDelegate)]) 
    {
       [refreshViewControllerDelegate performSelectorOnMainThread:@selector(refreshViewController:) withObject:@"YES" waitUntilDone:NO];                
    }

...
@end


#import "AppDelegate.h"

@interface Tab4ViewController<ReloadViewControllerDelegate>
...
@end

@implementation Tab4ViewController

...
appDelegate.refreshViewControllerDelegate = self;
...

@end

【讨论】:

    【解决方案4】:

    您正在调用此代码:

    if ([refreshViewControllerDelegate conformsToProtocol:@protocol(ReloadViewControllerDelegate)]) 
    

    但是refreshViewControllerDelegate是这样的:

    id refreshViewControllerDelegate;
    

    conformsToProtocol 检查对象是否声明它符合协议,而你的却没有。如果您想指定对协议的一致性,您需要:

    id<ReloadViewControllerDelegate> refreshViewControllerDelegate;
    

    编辑

    好的,关于performSelectorOnMainThread 问题...该方法在 NSThread 的类别中提供,并且未在 NSObject 协议中声明。所以,如果你想调用它,那么你需要将你的类型声明为 NSObject,它符合你的协议。

    NSObject<ReloadViewControllerDelegate> refreshViewControllerDelegate;
    

    编辑

    好的,看起来这不是一个关于使用协议的简单问题,而是一个完整的教程。由于 SO 不是这样的地方,我将尝试简要介绍一下...

    协议是一个接口声明。

    @protocol ReloadChatViewControllerDelegate <NSObject>
    - (void)refreshViewController:(NSString *)result;
    @end
    

    这表示镇上有一个新协议,名称为ReloadChatViewControllerDelegate,它也符合NSObject 协议。任何采用新协议的类都必须提供refreshViewController 的实现。您可以通过添加 @optional 部分来使协议方法成为可选方法。

    @protocol ReloadChatViewControllerDelegate <NSObject>
    - (void)refreshViewController:(NSString *)result;
    @optional
    - (void)optRefresh;
    @end
    

    现在,让我们将协议的采用留到以后。假设您正在编写通用代码,并且您只想知道给定的对象是否符合协议,如果符合,请在其上调用方法。比如……

    @interface Bar : NSObject
    @property (nonatomic, weak) NSObject<ReloadChatViewControllerDelegate>  *refreshViewControllerDelegate;
    - (void)blarg;
    @end
    

    现在,Bar 类提供了一个委托属性,以便它可以提供一些对象来帮助它完成一些工作。但是,该委托对象必须至少是一个NSObject,并且符合ReloadChatViewControllerDelegate 协议。

    现在,ObjC(和 C)是相当宽松的,所以你可以强制一个对象是你想要的任何类型,但是你应该得到你得到的崩溃。现在,当调用blarg 时,会通知委托人做一些工作。

    由于委托的属性类型已经表明它符合给定的协议,因此无需检查是否符合。我们可以调用委托方法。请注意,我们必须查看对象是否实现了任何可选的协议方法。

    @implementation Bar
    @synthesize refreshViewControllerDelegate = _refreshViewControllerDelegate;
    - (void)blarg {
        // Do something, then invoke the delegate
        [self.refreshViewControllerDelegate
            performSelectorOnMainThread:@selector(refreshViewController:)
                             withObject:@"YES"
                          waitUntilDone:NO];
        if ([self.refreshViewControllerDelegate respondsToSelector:@selector(optRefresh)]) {
            [self.refreshViewControllerDelegate optRefresh];
        }
    }
    @end
    

    但是,如果您想成为通用的,并接受任何对象作为委托(也许您想让委托符合某些给定的协议是可选的),那么您可以接受一个普通的id,然后检查看到它符合。在这种情况下,您可以将您的委托声明为一个 id(或其他类型)。

    @property (nonatomic, weak) id refreshViewControllerDelegate;
    

    现在,在您的代码中,您需要检查一致性。

    - (void)blarg {
        // Do something, then invoke the delegate
        if ([self.refreshViewControllerDelegate
                conformsToProtocol:@protocol(ReloadChatViewControllerDelegate)]) {
            [self.refreshViewControllerDelegate
                performSelectorOnMainThread:@selector(refreshViewController:)
                                 withObject:@"YES" waitUntilDone:NO];
            if ([self.refreshViewControllerDelegate
                    respondsToSelector:@selector(optRefresh)]) {
                [self.refreshViewControllerDelegate optRefresh];
            }
        }
    }
    

    好的,现在您已经定义了一个协议,并且您拥有调用该协议上的方法的代码。两个警告。

    首先,必须将委托设置为一个对象。 nil对任何方法都会响应false,所以它当然不会符合,发送任何消息时也不做任何事情。

    其次,您必须确保您的委托声明符合协议。仅仅实现方法不符合。如果一个类没有明确指定符合协议,那么conformsToProtocol 将返回 false,即使它实现了协议的方法。

    所以,让我们指定一些类,通过遵守协议来充当我们的委托。

    @interface Foo : NSObject<ReloadChatViewControllerDelegate>
    - (void)refreshViewController:(NSString *)result;
    @end
    @implementation Foo
    - (void)refreshViewController:(NSString *)result {
        NSLog(@"Look, ma, I'm refreshed with %@", result);
    }
    @end
    

    符合协议,提供强制方法的实现,省略可选方法。

    现在,如果你运行这段代码,你应该会看到这段精彩的代码。

    Foo *foo = [[Foo alloc] init];
    Bar *bar = [[Bar alloc] init];
    bar.refreshViewControllerDelegate = foo;
    [bar blarg];
    

    【讨论】:

    • 我已经尝试过您的代码,但它显示了我在问题中提到的警告。请你帮助我好吗。谢谢。
    • 谢谢。我使用了如下代码并出现错误。不熟悉iOS开发。请不要误会我的问题。错误消息是:“接口类型不能静态分配”。我的代码是 NSObject *reloadChatViewControllerDelegate;和@property(非原子,保留)NSObject *reloadChatViewControllerDelegate;。我知道这是错误的,但我不知道如何解决。请帮我。谢谢。
    • 很抱歉,您正在绕圈子,您的问题一直在变化。编辑您的原始问题,清理它,并提供一个完整、简短的示例来说明您遇到的问题。
    • 谢谢。我已经编辑了我的问题。请帮助我做到这一点。谢谢。
    • "但是 refreshViewControllerDelegate 是这样的" 变量具有什么静态类型并不重要。静态对象指针类型是一种编译时错觉。实际运行时类型是运行程序时唯一重要的事情。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多