声明委托协议

sam*_*mir 5 iphone objective-c ios

我想知道protocol在同一个类中声明a 并在单独的文件中声明它时有什么区别; 例如:

#import <UIKit/UIKit.h>

@class MyClassA;

@protocol MyDelegate <NSObject>

@required
- (MyClassA*)myMythod;

@optional
- (void)anOtherMethod:(NSString*)ID;

@end

@interface MyClassB : UIViewController <UITableViewDataSource, UITableViewDelegate>

@property (nonatomic, assign) id <MyDelegate> delegate;
......
Run Code Online (Sandbox Code Playgroud)

在这里,我使用MyClassB在同一文件中声明协议delagate,我可以在单独的源文件中声明它(协议委托).在同一个文件中将它与类和单独的文件中声明它有什么区别?谢谢!

Nat*_*ate 8

肯定有微妙的差异.

如果您正在讨论的协议是一个特定类使用的委托,例如MySpecialViewController,和MySpecialViewControllerDelegate,那么您可能非常希望将这两个声明保留在同一个标​​头中.例如,如果另一个类要实现该协议,那么它可能在逻辑上依赖于MySpecialViewController该类.因此,您不会引入任何其他依赖项.

但是,(至少)使用协议还有另一个重要原因.您可能试图解耦两个类之间的双向依赖关系.当然,编译器不会让两个标头#import相互连接.但是,即使你将一个类移动#import.m文件中,通常也会有一个糟糕的设计标志,即让两个类完全了解彼此的完整API.

解除这种关系的一种方法是让一个类只通过另一个实现的协议来识别另一个.也许Parent拥有并创造了这个Child阶级#import "Child.h".但是,Child还需要调用foo:bar:方法Parent.你可以做一个FooProtocol:

@protocol FooProtocol
  - (void) foo: (int) arg1 bar: (BOOL) arg2;
@end
Run Code Online (Sandbox Code Playgroud)

然后在Parent.h中:

@interface Parent : SomeBaseClass<FooProtocol> {
}
Run Code Online (Sandbox Code Playgroud)

允许Child这样做:

@interface Child {
}
@property (assign) id<FooProtocol> fooHandler;
Run Code Online (Sandbox Code Playgroud)

并使用它

[fooHandler foo: 1 bar: YES];
Run Code Online (Sandbox Code Playgroud)

这使得孩子没有直接依赖于Parent类(或Parent.h).但是,这仅在您保留FooProtocolFooProtocol.h中的声明时才有效,而不是在Parent.h中.同样,如果FooProtocol只使用Child它,那么它保存在Child.h中是有意义的,但如果该协议被其他类使用,则可能不会Child.

因此,总而言之,如果要保留分离类之间相互依赖关系的最大能力,或者鼓励在设计中更好地分离,请将协议保存在单独的标头中.