GCDMulticastDelegate源代码阅读

最早注意到这个类是之前搞XMPP的时候,使用了一个开源库:https://github.com/robbiehanson/XMPPFramework,在研究其中的插件机制的时候,发现其中的核心就是这个类,是一个一对多的代理机制。之前读过一次源代码,但是一直比较忙,没有来得及总结。这两天抽出来时间读源代码,细看了一下这个类的实现,既简单又巧妙,写的非常好。还有一个类似的实现,MultiDelegate,已经封装为pods:https://github.com/aleph7/MultiDelegate

这个类实现的技术基础是OC的消息动态解析与转发,通过这些机制进行封装,很巧妙实现了一对多的delegate机制,避免了有这种需求的时候,都需要自己去维护这种逻辑的问题。代码不长,阅读难度也不是很大。调用的时候,核心是methodSignatureForSelector: -> forwardInvocation: -> doesNotRecognizeSelector逻辑的重写,关于这部分,可以参考我之前关于OC消息动态解析与转发的一篇博客,http://blog.csdn.net/colorapp/article/details/43951709。这里需要注意的一点是,GCDMulticastDelegate不能使用respondToSelector进行检测,但是其内部已经对不能实现调用的方法进行了处理,不会引发Exception。

总体而言,是其中的代码实现思路很有意思,可以作为参考。代码内部有几个需要注意的地方:
1. methodSignatureForSelector: 这个方法必须实现,否则在forwardInvocation之前会引发crash,这里的实现方式是获取其中包含其他的类的method的实现,可以借鉴一下。
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
	for (GCDMulticastDelegateNode *node in delegateNodes)
	{
		id nodeDelegate = node.delegate;
		#if __has_feature(objc_arc_weak) && !TARGET_OS_IPHONE
		if (nodeDelegate == [NSNull null])
			nodeDelegate = node.unsafeDelegate;
		#endif
		
		NSMethodSignature *result = [nodeDelegate methodSignatureForSelector:aSelector];
		
		if (result != nil)
		{
			return result;
		}
	}
	
	// This causes a crash...
	// return [super methodSignatureForSelector:aSelector];
	
	// This also causes a crash...
	// return nil;
	
	return [[self class] instanceMethodSignatureForSelector:@selector(doNothing)];
}



2. duplicateInvocation: 这个方法的实现比较有意思,可以作为参考,后续可以用到。
- (NSInvocation *)duplicateInvocation:(NSInvocation *)origInvocation
{
	NSMethodSignature *methodSignature = [origInvocation methodSignature];
	
	NSInvocation *dupInvocation = [NSInvocation invocationWithMethodSignature:methodSignature];
	[dupInvocation setSelector:[origInvocation selector]];
	
	NSUInteger i, count = [methodSignature numberOfArguments];
	for (i = 2; i < count; i++)
	{
		const char *type = [methodSignature getArgumentTypeAtIndex:i];
		
		if (*type == *@encode(BOOL))
		{
			BOOL value;
			[origInvocation getArgument:&value atIndex:i];
			[dupInvocation setArgument:&value atIndex:i];
		}
		else if (*type == *@encode(char) || *type == *@encode(unsigned char))
		{
			char value;
			[origInvocation getArgument:&value atIndex:i];
			[dupInvocation setArgument:&value atIndex:i];
		}
		else if (*type == *@encode(short) || *type == *@encode(unsigned short))
		{
			short value;
			[origInvocation getArgument:&value atIndex:i];
			[dupInvocation setArgument:&value atIndex:i];
		}
		else if (*type == *@encode(int) || *type == *@encode(unsigned int))
		{
			int value;
			[origInvocation getArgument:&value atIndex:i];
			[dupInvocation setArgument:&value atIndex:i];
		}
		else if (*type == *@encode(long) || *type == *@encode(unsigned long))
		{
			long value;
			[origInvocation getArgument:&value atIndex:i];
			[dupInvocation setArgument:&value atIndex:i];
		}
		else if (*type == *@encode(long long) || *type == *@encode(unsigned long long))
		{
			long long value;
			[origInvocation getArgument:&value atIndex:i];
			[dupInvocation setArgument:&value atIndex:i];
		}
		else if (*type == *@encode(double))
		{
			double value;
			[origInvocation getArgument:&value atIndex:i];
			[dupInvocation setArgument:&value atIndex:i];
		}
		else if (*type == *@encode(float))
		{
			float value;
			[origInvocation getArgument:&value atIndex:i];
			[dupInvocation setArgument:&value atIndex:i];
		}
		else if (*type == '@')
		{
			void *value;
			[origInvocation getArgument:&value atIndex:i];
			[dupInvocation setArgument:&value atIndex:i];
		}
		else if (*type == '^')
		{
			void *block;
			[origInvocation getArgument:&block atIndex:i];
			[dupInvocation setArgument:&block atIndex:i];
		}
		else
		{
			NSString *selectorStr = NSStringFromSelector([origInvocation selector]);
			
			NSString *format = @"Argument %lu to method %@ - Type(%c) not supported";
			NSString *reason = [NSString stringWithFormat:format, (unsigned long)(i - 2), selectorStr, *type];
			
			[[NSException exceptionWithName:NSInvalidArgumentException reason:reason userInfo:nil] raise];
		}
	}
	
	[dupInvocation retainArguments];
	
	return dupInvocation;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1)解码支持的协议特性:h.264 main profile完整规格,严格参照2005年3月正式发布的协议文档(T-REC-H.264-200503-P!!MSW-E.doc)实现。Main profile的特性参见协议附录A对profile以及level的描述。 2)解码库采用的测试工具集:ALLEGRO,HHI,JVT提供的baseline(FMO/ASO特性除外), main profile专业测试码流,以及超过20家IPTV厂家的商用码流。其中专业测试码流是业界用来确保解码芯片规格完备的利器。 3)解码容错处理:重用相同协议规格解码芯片IP验证使用的工具集,含盖了几乎所有的业务功能,边界条件,系统异常等问题的测试用例。 4)是针对X86平台开发的在windows系统下的版本:采用intel的编译器,slice以上层解码主要采用C语言实现,宏块层解码大量使用了MMX,SSE2技术进行高性能并行解码设计。由于main profile的复杂度比较高,不推荐在不支持MMX,SSE2技术的计算机上使用本解码库产品。 5)产品标杆:在性能指标上一直参照业界性能最佳coreAVC解码库进行对比开发,目前纯解码性能稳定在其120%以上,而且对协议规格的遵守方面则具有明显优势。本解码库吸收了JM 10.2在调测ALLEGRO等专业测试码流时发现的若干问题,而coreAVC提供的demo程序只能通过一些最基本的测试码流。业界比较知名的公司还有ateme, elecard和cyberlink。 6)接口形式:提供5个独立的API函数(open, close, decode, get, set)。其中decode函数只负责解析接收到的用户指定长度的符合协议附录B描述的视频流;在解码库内部维护解码图像缓冲区,通过get和set函数来实现播放显示与解码对重构图像的地址交互,避免YUV数据的多次拷贝。 技术支持联系:kwen_zhang@hotmail.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值