ReactiveCocoa 学习笔记十九(NSObject)

本文详细介绍了ReactiveCocoa框架如何通过分类扩展NSObject类,提供响应式编程特性,如监听对象销毁、属性变化及方法调用。特别聚焦于RACDeallocating、RACDescription、RACKVOWrapper、RACLifting、RACPropertySubscribing和RACSelectorSignal等分类的功能和实现原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

NSObject 分类

为了提供更多特性,ReactiveCocoa 框架为 NSObject 类扩展了多个分类。所以,所有 NSObject 的子类都可以调用这些分类中的方法。

RACDeallocating

RACDeallocating 分类中提供了一个 rac_willDeallocSignal 方法,该方法可以返回一个信号流,当该类的实例被释放时,这个信号流会立即传递一个结束信号量。所以,可以订阅这个信号流,从而在实例对象销毁时,执行一些操作。

@property (atomic, readonly, strong) RACCompoundDisposable *rac_deallocDisposable;

- (RACSignal *)rac_willDeallocSignal;

该特性实现的主要方法如下:

static void swizzleDeallocIfNeeded(Class classToSwizzle) {
	@synchronized (swizzledClasses()) {
		NSString *className = NSStringFromClass(classToSwizzle);
		if ([swizzledClasses() containsObject:className]) return;

		SEL deallocSelector = sel_registerName("dealloc");

		__block void (*originalDealloc)(__unsafe_unretained id, SEL) = NULL;

		id newDealloc = ^(__unsafe_unretained id self) {
			RACCompoundDisposable *compoundDisposable = objc_getAssociatedObject(self, RACObjectCompoundDisposable);
			[compoundDisposable dispose];

			if (originalDealloc == NULL) {
				struct objc_super superInfo = {
					.receiver = self,
					.super_class = class_getSuperclass(classToSwizzle)
				};

				void (*msgSend)(struct objc_super *, SEL) = (__typeof__(msgSend))objc_msgSendSuper;
				msgSend(&superInfo, deallocSelector);
			} else {
				originalDealloc(self, deallocSelector);
			}
		};
		
		IMP newDeallocIMP = imp_implementationWithBlock(newDealloc);
		
		if (!class_addMethod(classToSwizzle, deallocSelector, newDeallocIMP, "v@:")) {

			Method deallocMethod = class_getInstanceMethod(classToSwizzle, deallocSelector);

			originalDealloc = (__typeof__(originalDealloc))method_getImplementation(deallocMethod);
			
			originalDealloc = (__typeof__(originalDealloc))method_setImplementation(deallocMethod, newDeallocIMP);
		}

		[swizzledClasses() addObject:className];
	}
}

原理是利用 OC 语言的运行时特性,为指定的类定义 dealloc 方法。当然,若 dealloc 方法已经实现了,则要将原方法保存替换,而后执行。

  1. swizzledClasses() 返回一个集合,如果该集合已经包含了指定的 classToSwizzle 类,那么说明 dealloc 方法已经经过相应的调整,直接返回。
  2. 接着定义一个 originalDealloc 变量用来保存可能存在的 dealloc 实现方法。
  3. 定义一个 newDealloc 代码块,即是后面要设置的 dealloc 实现方法,该方法会先调用 compoundDisposable 的 dispose 方法,实际会传递一个结束信号量。然后,如果存在原 dealloc 方法,就执行,否则执行父类的 dealloc 方法。
  4. 使用 imp_implementationWithBlock 函数和参数 newDealloc 代码块创建一个实现方法的变量 newDeallocIMP 。
  5. 使用 class_addMethod 函数为指定的 classToSwizzle 类添加 dealloc 实现方法,如果添加失败,那么说明已经存在该实现方法,则先对其进行保存,而后用 method_setImplementation 函数重写设置。

另外,也可以将相关的操作放在 rac_deallocDisposable 属性中。

RACDescription

在 RACDescription 分类中,主要是声明了一个 RACDescription 函数,该函数会根据参数的类型来返回相应的描述。

NSString *RACDescription(id object) {
	if (getenv("RAC_DEBUG_SIGNAL_NAMES") != NULL) {
		if ([object respondsToSelector:@selector(rac_description)]) {
			return [object rac_description];
		} else {
			return [[NSString alloc] initWithFormat:@"<%@: %p>", [object class], object];
		}
	} else {
		return @"(description skipped)";
	}
}

不过,该方法只适用于调试模式。

RACKVOWrapper

RACKVOWrapper 中提供了一个方法,该方法对 KVO 模式进行了封装。并且,当监听的属性声明的是 weak 特征时,同样也会调用 block 代码块。并且,监听者和被监听者任意一个被销毁时,监听也会自动移除,而不用手动移除监听。

- (RACDisposable *)rac_observeKeyPath:(NSString *)keyPath 
 									options:(NSKeyValueObservingOptions)options 
 									observer:(__weak NSObject *)weakObserver 
 									block:(void (^)(id, NSDictionary *, BOOL, BOOL))block 
{
	//block 和 keyPath 不能为空
	NSCParameterAssert(block != nil);
	NSCParameterAssert(keyPath.rac_keyPathComponents.count > 0);

	keyPath = [keyPath copy];

	NSObject *strongObserver = weakObserver;

	NSArray *keyPathComponents = keyPath.rac_keyPathComponents;
	
	//keyPath 是否只包含一个部分
	BOOL keyPathHasOneComponent = (keyPathComponents.count == 1);
	
	//keyPath 的第一个部分
	NSString *keyPathHead = keyPathComponents[0];
	
	//keyPath 的剩余部分
	NSString *keyPathTail = keyPath.rac_keyPathByDeletingFirstKeyPathComponent;

	//清理对象
	RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];

	//第一个路径值的清理对象
	RACSerialDisposable *firstComponentSerialDisposable = [RACSerialDisposable serialDisposableWithDisposable:[RACCompoundDisposable compoundDisposable]];
	
	//获取清理对象
	RACCompoundDisposable * (^firstComponentDisposable)(void) = ^{
		return (RACCompoundDisposable *)firstComponentSerialDisposable.disposable;
	};

	[disposable addDisposable:firstComponentSerialDisposable];

	//是否因该添加销毁监听,默认不添加
	BOOL shouldAddDeallocObserver = NO;

	//获取当前类的指定属性 property
	objc_property_t property = class_getProperty(object_getClass(self), keyPathHead.UTF8String);
	
	if (property != NULL) {
	
		//获取属性 property 的特性
		rac_propertyAttributes *attributes = rac_copyPropertyAttributes(property);
		if (attributes != NULL) {
			@onExit {
				free(attributes);
			};

			BOOL isObject = attributes->objectClass != nil || strstr(attributes->type, @encode(id)) == attributes->type;
			BOOL isProtocol = attributes->objectClass == NSClassFromString(@"Protocol");
			BOOL isBlock = strcmp(attributes->type, @encode(void(^)())) == 0;
			BOOL isWeak = attributes->weak;

			//属性是类,并且为弱引用,不是代码块,不是协议,才可以添加销毁监听
			shouldAddDeallocObserver = isObject && isWeak && !isBlock && !isProtocol;
		}
	}

	//为指定值添加销毁监听的代码块
	void (^addDeallocObserverToPropertyValue)(NSObject *) = ^(NSObject *value) {
	
		//先进行判断,是否可以添加销毁监听
		if (!shouldAddDeallocObserver) return;

		//如果监听者是监听路径上的一个值,那么直接返回,因为监听者本身被销毁并不在监听范围内
		if (value == weakObserver) return;

		NSDictionary *change = @{
			NSKeyValueChangeKindKey: @(NSKeyValueChangeSetting),
			NSKeyValueChangeNewKey: NSNull.null,
		};

		//获取指定值的清理对象
		RACCompoundDisposable *valueDisposable = value.rac_deallocDisposable;
		
		//将 block 回调封装为一个清理任务
		RACDisposable *deallocDisposable = [RACDisposable disposableWithBlock:^{
			block(nil, change, YES, keyPathHasOneComponent);
		}];

		//将清理任务添加到指定值的清理对象中
		[valueDisposable addDisposable:deallocDisposable];
		
		//向第一个路径值的清理对象中添加一个任务,该任务是移除 deallocDisposable 清理任务
		[firstComponentDisposable() addDisposable:[RACDisposable disposableWithBlock:^{
			[valueDisposable removeDisposable:deallocDisposable];
		}]];
	};

	//为第一个路径值后面的路径添加 block 回调任务
	void (^addObserverToValue)(NSObject *) = ^(NSObject *value) {
		RACDisposable *observerDisposable = [value rac_observeKeyPath:keyPathTail 
												                     options:(options & ~NSKeyValueObservingOptionInitial)
												                    observer:weakObserver 
												                       block:block];
		[firstComponentDisposable() addDisposable:observerDisposable];
	};

	//监听第一个路径值的变化,但是不包括值的初始化情况
	NSKeyValueObservingOptions trampolineOptions = (options | NSKeyValueObservingOptionPrior) & ~NSKeyValueObservingOptionInitial;
	RACKVOTrampoline *trampoline = [[RACKVOTrampoline alloc] initWithTarget:self 
												                           observer:strongObserver 
												                           keyPath:keyPathHead 
												                           options:trampolineOptions 
												                           block:^(id trampolineTarget, id trampolineObserver, NSDictionary *change) {
		
		//当接收到前一个通知时,清理第一个路径值的相关任务
		if ([change[NSKeyValueChangeNotificationIsPriorKey] boolValue]) {
			[firstComponentDisposable() dispose];
			
			//如果设置的监听有 NSKeyValueObservingOptionPrior ,则执行 block
			if ((options & NSKeyValueObservingOptionPrior) != 0) {
				block([trampolineTarget valueForKeyPath:keyPath], change, NO, keyPathHasOneComponent);
			}

			return;
		}

		//获取变化的值
		NSObject *value = [trampolineTarget valueForKey:keyPathHead];

		//如果值变为 nil ,那么直接调用 block 即可
		if (value == nil) {
			block(nil, change, NO, keyPathHasOneComponent);
			return;
		}

		//将原任务清理,添加新的任务
		RACDisposable *oldFirstComponentDisposable = [firstComponentSerialDisposable swapInDisposable:[RACCompoundDisposable compoundDisposable]];
		[oldFirstComponentDisposable dispose];

		//为指定值添加销毁监听
		addDeallocObserverToPropertyValue(value);

		//如果没有其他路径值,直接调用 block 代码
		if (keyPathHasOneComponent) {
			block(value, change, NO, keyPathHasOneComponent);
			return;
		}

		//为剩余的路径值添加监听
		addObserverToValue(value);
		
		//调用 block 代码
		block([value valueForKeyPath:keyPathTail], change, NO, keyPathHasOneComponent);
	}];

	//添加停止监听的清理任务
	[disposable addDisposable:trampoline];

	//获取路径的第一个值
	NSObject *value = [self valueForKey:keyPathHead];
	if (value != nil) {
	
		//添加销毁监听
		addDeallocObserverToPropertyValue(value);

		if (!keyPathHasOneComponent) {
		
			//添加剩余路径的监听
			addObserverToValue(value);
		}
	}

	//监听选项包含初始化选项时,调用 block 代码并传递初始化值
	if ((options & NSKeyValueObservingOptionInitial) != 0) {
		id initialValue = [self valueForKeyPath:keyPath];
		NSDictionary *initialChange = @{
			NSKeyValueChangeKindKey: @(NSKeyValueChangeSetting),
			NSKeyValueChangeNewKey: initialValue ?: NSNull.null,
		};
		block(initialValue, initialChange, NO, keyPathHasOneComponent);
	}

	//将监听清理任务加入监听者和当前对象的销毁清理任务中
	RACCompoundDisposable *observerDisposable = strongObserver.rac_deallocDisposable;
	RACCompoundDisposable *selfDisposable = self.rac_deallocDisposable;
	[observerDisposable addDisposable:disposable];
	[selfDisposable addDisposable:disposable];

	//返回一个清理对象,其包含停止监听的任务
	return [RACDisposable disposableWithBlock:^{
		[disposable dispose];
		[observerDisposable removeDisposable:disposable];
		[selfDisposable removeDisposable:disposable];
	}];
}

从上面的代码分析,可以看出,对于传递的 keyPath 中的每个路径值,都会进行监听(监听者 observer 除外),不过其向 block 中传递的参数都是全路径所对应的值。

RACLifting

RACLifting 分类中定义了三个方法用来实现当前类中方法的调用,只是方法的参数是通过信号流传递的。

- (RACSignal *)rac_liftSelector:(SEL)selector withSignals:(RACSignal *)firstSignal, ... NS_REQUIRES_NIL_TERMINATION;

- (RACSignal *)rac_liftSelector:(SEL)selector withSignalsFromArray:(NSArray<RACSignal *> *)signals;

这两个方法调用当前类的 selector 方法,而参数同 signal 相对应。当每个信号流都传递了信号量时,方法会被调用,而之后,每当任意一个信号流传递了信号量后,都会去执行一次 selecor 方法。只是,这两个方法,最终都是调用了下面的这个方法。

- (RACSignal *)rac_liftSelector:(SEL)selector withSignalOfArguments:(RACSignal *)arguments {
	NSCParameterAssert(selector != NULL);
	NSCParameterAssert(arguments != nil);
	
	@unsafeify(self);
	
	NSMethodSignature *methodSignature = [self methodSignatureForSelector:selector];
	NSCAssert(methodSignature != nil, @"%@ does not respond to %@", self, NSStringFromSelector(selector));
	
	return [[[[arguments
		takeUntil:self.rac_willDeallocSignal]
		map:^(RACTuple *arguments) {
			@strongify(self);
			
			NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
			invocation.selector = selector;
			invocation.rac_argumentsTuple = arguments;
			[invocation invokeWithTarget:self];
			
			return invocation.rac_returnValue;
		}]
		replayLast]
		setNameWithFormat:@"%@ -rac_liftSelector: %s withSignalsOfArguments: %@", RACDescription(self), sel_getName(selector), arguments];
}

这三个方法的返回值是一个信号流,该信号流传递的是方法被调用的返回值,如果没有返回值,那么传递 RACUnit.defaultUnit 信号量。

RACPropertySubscribing

RACPropertySubscribing 分类实际是对 RACKVOWrapper 分类的进一步封装,其中的方法,实际都是调用了 RACKVOWrapper 中的方法。

- (RACSignal *)rac_valuesForKeyPath:(NSString *)keyPath observer:(__weak NSObject *)observer;

- (RACSignal<RACTwoTuple<id, NSDictionary *> *> *)rac_valuesAndChangesForKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)observer;

上面两个方法都是对当前对象指定路径下属性的变化监听,返回的信号流传递了变化的值或变化的信息。

RACSelectorSignal

RACSelectorSignal 分类提供了两个方法,用来监听指定方法的调用,返回的信号流传递的信号量是调用方法时使用的参数。

不同于 RACLifting 分类,其是参数传递引发方法的调用,而 RACSelectorSignal 分类的方法是方法的调用,导致参数在信号流中的传递。

- (RACSignal<RACTuple *> *)rac_signalForSelector:(SEL)selector;

- (RACSignal<RACTuple *> *)rac_signalForSelector:(SEL)selector fromProtocol:(Protocol *)protocol;

内部方法

上面两个方法都调用了内部创建的函数:

static RACSignal *NSObjectRACSignalForSelector(NSObject *self, SEL selector, Protocol *protocol)

在理解这个函数之前,先说明其它相关的函数。


static SEL RACAliasForSelector(SEL originalSelector);

RACAliasForSelector 函数为指定的选择器添加一个前缀 rac_alias_ 后返回这个新的选择器。


static NSMutableSet *swizzledClasses();

swizzledClasses 函数返回一个集合,该集合保存所有已经进行交换了的类。


static BOOL RACForwardInvocation(id self, NSInvocation *invocation) {
	SEL aliasSelector = RACAliasForSelector(invocation.selector);
	RACSubject *subject = objc_getAssociatedObject(self, aliasSelector);

	Class class = object_getClass(invocation.target);
	BOOL respondsToAlias = [class instancesRespondToSelector:aliasSelector];
	if (respondsToAlias) {
		invocation.selector = aliasSelector;
		[invocation invoke];
	}

	if (subject == nil) return respondsToAlias;

	[subject sendNext:invocation.rac_argumentsTuple];
	return YES;
}
  1. 根据参数 invocation 获取别名选择器 aliasSelector
  2. 根据选择器 aliasSelector 获取信号流 subject
  3. 根据参数 invocation 获取消息接收类 class
  4. 确认 class 类中是否能够处理 aliasSelector 消息,如果能,就处理。
  5. 如果 subject 为空,直接返回 respondsToAlias
  6. 如果 subject 存在,则发送相关参数,最后返回 YES

static void RACSwizzleForwardInvocation(Class class) {
	SEL forwardInvocationSEL = @selector(forwardInvocation:);
	Method forwardInvocationMethod = class_getInstanceMethod(class, forwardInvocationSEL);

	void (*originalForwardInvocation)(id, SEL, NSInvocation *) = NULL;
	if (forwardInvocationMethod != NULL) {
		originalForwardInvocation = (__typeof__(originalForwardInvocation))method_getImplementation(forwardInvocationMethod);
	}

	id newForwardInvocation = ^(id self, NSInvocation *invocation) {
		BOOL matched = RACForwardInvocation(self, invocation);
		if (matched) return;

		if (originalForwardInvocation == NULL) {
			[self doesNotRecognizeSelector:invocation.selector];
		} else {
			originalForwardInvocation(self, forwardInvocationSEL, invocation);
		}
	};

	class_replaceMethod(class, forwardInvocationSEL, imp_implementationWithBlock(newForwardInvocation), "v@:@");
}

为指定的 class 类创建新的 forwardInvocation: 实现方法,该方法当实际要调用的方法不存在时调用。

  1. 如果当前类已经实现了 forwardInvocation: 方法,那么就将该实现保存下来。
  2. 在新的实现方法中,首先会去尝试调用原来要调用的方法的别名方法,如果成功,则在信号流中传递方法中使用的参数,否则,就调用原 forwardInvocation: 实现方法,如果没实现,就发送一个未识别方法错误。

static void RACSwizzleRespondsToSelector(Class class) {
	SEL respondsToSelectorSEL = @selector(respondsToSelector:);

	Method respondsToSelectorMethod = class_getInstanceMethod(class, respondsToSelectorSEL);
	BOOL (*originalRespondsToSelector)(id, SEL, SEL) = (__typeof__(originalRespondsToSelector))method_getImplementation(respondsToSelectorMethod);

	id newRespondsToSelector = ^ BOOL (id self, SEL selector) {
		Method method = rac_getImmediateInstanceMethod(class, selector);

		if (method != NULL && method_getImplementation(method) == _objc_msgForward) {
			SEL aliasSelector = RACAliasForSelector(selector);
			if (objc_getAssociatedObject(self, aliasSelector) != nil) return YES;
		}

		return originalRespondsToSelector(self, respondsToSelectorSEL, selector);
	};

	class_replaceMethod(class, respondsToSelectorSEL, imp_implementationWithBlock(newRespondsToSelector), method_getTypeEncoding(respondsToSelectorMethod));
}

该方法会为指定的 class 类重新指定 respondsToSelector: 的实现方法,用来确定该类是否能够响应指定的消息。

  1. 先将原 respondsToSelector: 的实现方法保存下来
  2. 定义新的实现方法,先遍历指定类的所有方法查找指定的方法,如果能找到该方法,并且其实现方法为 _objc_msgForward,那么则判断与指定方法相关的别名方法是否关联了信号流,如果有,就返回 YES 。而遍历结束后,没有找到指定的方法,就执行原 respondsToSelector: 的实现方法。

static void RACSwizzleGetClass(Class class, Class statedClass) {
	SEL selector = @selector(class);
	Method method = class_getInstanceMethod(class, selector);
	IMP newIMP = imp_implementationWithBlock(^(id self) {
		return statedClass;
	});
	class_replaceMethod(class, selector, newIMP, method_getTypeEncoding(method));
}

该方法将修改指定的 class 类的 class 方法,使其返回 statedClass 类的类型。


static void RACSwizzleMethodSignatureForSelector(Class class) {
	IMP newIMP = imp_implementationWithBlock(^(id self, SEL selector) {

		Class actualClass = object_getClass(self);
		Method method = class_getInstanceMethod(actualClass, selector);
		if (method == NULL) {
			struct objc_super target = {
				.super_class = class_getSuperclass(class),
				.receiver = self,
			};
			NSMethodSignature * (*messageSend)(struct objc_super *, SEL, SEL) = (__typeof__(messageSend))objc_msgSendSuper;
			return messageSend(&target, @selector(methodSignatureForSelector:), selector);
		}

		char const *encoding = method_getTypeEncoding(method);
		return [NSMethodSignature signatureWithObjCTypes:encoding];
	});

	SEL selector = @selector(methodSignatureForSelector:);
	Method methodSignatureForSelectorMethod = class_getInstanceMethod(class, selector);
	class_replaceMethod(class, selector, newIMP, method_getTypeEncoding(methodSignatureForSelectorMethod));
}

该方法为指定的 class 类重新定义 methodSignatureForSelector: 的实现方法,在新的实现方法中,会先查找指定类的指定方法,如果方法存在,那么就根据该方法的类型编码创建一个方法签名并返回,如果不存在,则调用父类的 methodSignatureForSelector: 方法。


static Class RACSwizzleClass(NSObject *self) {
	Class statedClass = self.class;
	Class baseClass = object_getClass(self);

	Class knownDynamicSubclass = objc_getAssociatedObject(self, RACSubclassAssociationKey);
	if (knownDynamicSubclass != Nil) return knownDynamicSubclass;

	NSString *className = NSStringFromClass(baseClass);

	if (statedClass != baseClass) {
		@synchronized (swizzledClasses()) {
			if (![swizzledClasses() containsObject:className]) {
				RACSwizzleForwardInvocation(baseClass);
				RACSwizzleRespondsToSelector(baseClass);
				RACSwizzleGetClass(baseClass, statedClass);
				RACSwizzleGetClass(object_getClass(baseClass), statedClass);
				RACSwizzleMethodSignatureForSelector(baseClass);
				[swizzledClasses() addObject:className];
			}
		}

		return baseClass;
	}

	const char *subclassName = [className stringByAppendingString:RACSubclassSuffix].UTF8String;
	Class subclass = objc_getClass(subclassName);

	if (subclass == nil) {
		subclass = objc_allocateClassPair(baseClass, subclassName, 0);
		if (subclass == nil) return nil;

		RACSwizzleForwardInvocation(subclass);
		RACSwizzleRespondsToSelector(subclass);

		RACSwizzleGetClass(subclass, statedClass);
		RACSwizzleGetClass(object_getClass(subclass), statedClass);

		RACSwizzleMethodSignatureForSelector(subclass);

		objc_registerClassPair(subclass);
	}

	object_setClass(self, subclass);
	objc_setAssociatedObject(self, RACSubclassAssociationKey, subclass, OBJC_ASSOCIATION_ASSIGN);
	return subclass;
}

RACSwizzleClass 函数会为指定的实例对象绑定一个动态类,这个类一般是由框架创建的子类。这个绑定的类的相关消息转发方法都是被处理的过的,参见上面的方法说明以及消息转发机制


static void RACCheckTypeEncoding(const char *typeEncoding);

该函数可以用来检查方法类型编码是否合法。


static const char *RACSignatureForUndefinedSelector(SEL selector) {
	const char *name = sel_getName(selector);
	NSMutableString *signature = [NSMutableString stringWithString:@"v@:"];

	while ((name = strchr(name, ':')) != NULL) {
		[signature appendString:@"@"];
		name++;
	}

	return signature.UTF8String;
}

该方法返回指定选择器的方法类型编码,并且默认参数都是 OC 对象。


RACSelectorSignal 分类中的两个方法实际都是调用的 NSObjectRACSignalForSelector 函数,其提供了三个参数:self,selector,protocol。

  1. 获取选择器 selector 的别名选择器。

  2. 如果已经绑定了相应的信号流,那么就直接返回该信号流。

  3. 为当前的实例对象 self 绑定一个类 class ,这个类的相关方法都经过了处理。

  4. 创建一个信号流绑定到当前的对象,如果该对象销毁,那么信号流结束传递信号量。

  5. 从绑定的 class 类中查找指定的 selector 选择器方法,如果没有找到相应的方法:

    1)如果参数 protocol 为空,那么便从 selector 中获取方法类型编码,否则就从协议中查找到指定方法并获取他的类型编码。

    2)检查编码是否合法。

    3)指定接收到 selector 消息时,进行转发。如果指定失败,就直接返回一个错误信号流。

  6. 如果指定的 selector 方法查询到了,并且不是转发给其他的方法 _objc_msgForward ,那么:

    1)获取方法的编码并检验其合法性。

    2)向 class 类中添加别名方法,并且其实现方法指向查询到的方法实现。

    3)指定 class 接收到 selector 消息后,便进行转发。

  7. 最后返回创建的 subject 信号流。

参考下面的源码:

static RACSignal *NSObjectRACSignalForSelector(NSObject *self, SEL selector, Protocol *protocol) {
	SEL aliasSelector = RACAliasForSelector(selector);

	@synchronized (self) {
		RACSubject *subject = objc_getAssociatedObject(self, aliasSelector);
		if (subject != nil) return subject;

		Class class = RACSwizzleClass(self);
		NSCAssert(class != nil, @"Could not swizzle class of %@", self);

		subject = [[RACSubject subject] setNameWithFormat:@"%@ -rac_signalForSelector: %s", RACDescription(self), sel_getName(selector)];
		objc_setAssociatedObject(self, aliasSelector, subject, OBJC_ASSOCIATION_RETAIN);

		[self.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{
			[subject sendCompleted];
		}]];

		Method targetMethod = class_getInstanceMethod(class, selector);
		if (targetMethod == NULL) {
			const char *typeEncoding;
			if (protocol == NULL) {
				typeEncoding = RACSignatureForUndefinedSelector(selector);
			} else {
				// Look for the selector as an optional instance method.
				struct objc_method_description methodDescription = protocol_getMethodDescription(protocol, selector, NO, YES);

				if (methodDescription.name == NULL) {
					// Then fall back to looking for a required instance
					// method.
					methodDescription = protocol_getMethodDescription(protocol, selector, YES, YES);
					NSCAssert(methodDescription.name != NULL, @"Selector %@ does not exist in <%s>", NSStringFromSelector(selector), protocol_getName(protocol));
				}

				typeEncoding = methodDescription.types;
			}

			RACCheckTypeEncoding(typeEncoding);

			// Define the selector to call -forwardInvocation:.
			if (!class_addMethod(class, selector, _objc_msgForward, typeEncoding)) {
				NSDictionary *userInfo = @{
					NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedString(@"A race condition occurred implementing %@ on class %@", nil), NSStringFromSelector(selector), class],
					NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Invoke -rac_signalForSelector: again to override the implementation.", nil)
				};

				return [RACSignal error:[NSError errorWithDomain:RACSelectorSignalErrorDomain code:RACSelectorSignalErrorMethodSwizzlingRace userInfo:userInfo]];
			}
		} else if (method_getImplementation(targetMethod) != _objc_msgForward) {
			// Make a method alias for the existing method implementation.
			const char *typeEncoding = method_getTypeEncoding(targetMethod);

			RACCheckTypeEncoding(typeEncoding);

			BOOL addedAlias __attribute__((unused)) = class_addMethod(class, aliasSelector, method_getImplementation(targetMethod), typeEncoding);
			NSCAssert(addedAlias, @"Original implementation for %@ is already copied to %@ on %@", NSStringFromSelector(selector), NSStringFromSelector(aliasSelector), class);

			// Redefine the selector to call -forwardInvocation:.
			class_replaceMethod(class, selector, _objc_msgForward, method_getTypeEncoding(targetMethod));
		}

		return subject;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值