讲解通过协议实现组件化解耦的直播demo。 现在是将各个组件代码和主工程放到了一个Git工程里,当然实际应该是放到不同Git工程的。
GitHub地址https://github.com/mlcldh/LCLive
主工程依赖这些组件。LCLive是主工程。 LCMediator是调度层中间件。 LCBase是基础模块,封装公共类和方法。LCShare是分享模块。LCUser是用户信息模块。 LCWeb是h5、weex模块。 LCChat是私信模块。 LCMomment是动态模块。LCMe是用户信息展示模块。LCLaunchModule是负责处理app启动后操作的模块。
Podfile如下:
platform :ios, '8.0'
use_frameworks!
source 'https://github.com/CocoaPods/Specs.git'
target 'LCLive' do
pod 'LCMediator', :path => '../LCMediator'
pod 'LCBase', :path => '../LCBase'
pod 'LCUser', :path => '../LCUser'
pod 'LCShare', :path => '../LCShare'
pod 'LCMe', :path => '../LCMe'
pod 'LCChat', :path => '../LCChat'
pod 'LCWeb', :path => '../LCWeb'
pod 'LCMoment', :path => '../LCMoment'
pod 'LCLaunch', :path => '../LCLaunch'
end
中间件是LCMediator,它里面定义了User、私信、Web、Moment等协议,供相应组件实现了和供其他组件调用。
通过NSClassFromString方法获取到类后,写代码让该类执行类方法时,Xcode不会给提示,毕竟Xcode无法只提供Class这一个类型就判断出具体是那种类。既然不给提示,就要自己将代码复制过去,然后编译也没问题。但如果复制成了其他类方法,只要这个类方法能够引用到,编译就不会报错,这样就会出问题了。这样因为Xcode对类方法编译不够友好,将所有组件协议方法都写成实例方法。
LCMediator的LCMediatorHeader里通过传入的组件协议返回实现该协议的类的实例。 方法LCModuleInstanceFromProtocol获取到的也就只是实例对象。调用组件协议实例时,不需要提前注册,LCModuleInstanceFromProtocol内部做了懒加载处理。
/**根据传入的组件协议返回实现该协议的类的对象*/
NS_INLINE id LCModuleInstanceFromProtocol(Protocol *protocol) {
NSString *className = NSStringFromProtocol(protocol);
Class aClass = NSClassFromString(className);
// NSLog(@"class %@,%@",className,aClass);
static NSMutableDictionary *modulesDictionary = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
modulesDictionary = [NSMutableDictionary dictionary];
});
id module = modulesDictionary[className];
if (!module) {
module = [[aClass alloc]init];
modulesDictionary[className] = module;
}
if ([module conformsToProtocol:protocol]){
return module;
}
return nil;
}
#define LCModuleInstance(module,LCModuleProtocol) id module = LCModuleInstanceFromProtocol(@protocol(LCModuleProtocol));
#define LCGetModuleInstance(LCModuleProtocol) ((id)(LCModuleInstanceFromProtocol(@protocol(LCModuleProtocol))))
/**用户信息模块*/
@protocol LCUserModule
/**用户id*/
- (NSString *)userId;
/**token*/
- (NSString *)token;
/**用户昵称*/
- (NSString *)nickname;
/**用户头像url地址*/
- (NSString *)avatarUrlString;
@end
@interface LCUserModule : NSObject
@end
@implementation LCUserModule
- (NSString *)userId {
return @"abc123100";
}
- (NSString *)token {
return @"qwe007what";
}
- (NSString *)nickname {
return @"李明";
}
- (NSString *)avatarUrlString {
return @"https://ss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=3843887011,4044287239&fm=173&app=25&f=JPEG?w=218&h=146&s=F81821D40331ABCC106BAA8003008088";
// return @"https://avatar.csdn.net/7/5/6/1_mlcldh.jpg?1532075030";
}
@end
_nicknameLabel.text = [LCGetModuleInstance(LCUserModule) nickname];
LCWeb是h5、weex模块。 LCWebModule里面实现协议提供跳转到H5的方法。
@implementation LCWebModule
- (void)pushWebViewControllerWithUrlString:(NSString *)urlString fromViewController:(UIViewController *)viewController {
LCWebViewController *webVC = [[LCWebViewController alloc]init];
webVC.urlString = urlString;
[viewController.navigationController pushViewController:webVC animated:YES];
}
@end
LCChat是私信模块。LCChatModule提供读取消息未读数和跳转到单例详情的方法。
@implementation LCChatModule
- (UIViewController *)sessionListViewController {
LCSessionListViewController *vc = [[LCSessionListViewController alloc]init];
return vc;
}
- (NSUInteger)unreadCount {
return 3;
}
- (void)pushUserChatViewControllerWithUserId:(NSString *)userId fromViewController:(UIViewController *)viewController {
LCUserChatViewController *userChatVC = [[LCUserChatViewController alloc]init];
[viewController.navigationController pushViewController:userChatVC animated:YES];
}
@end
优点:
缺点:
使用注意事项: