ios Bind绑定

   不管是用mvc还是mvvm的架构,我们都需要一点就是model的改变能够及时同步到相关部件中。就类似月观察者模型,在ios中可以通过kvo来完成这样的事情,但是每次都是用这个样的方式,就回让代码混乱。在这里可以采用THBinder在github来完成这个任务。同时我对这个代码进行了一点处理,这样就使用一个简单的宏来完成,不要保存THBinder实例了。


#import "THBinder.h"
#import "THObserver.h"
#import <objc/runtime.h>
#import <objc/message.h>

#define TMBindDictoryKey                "__TMBindDictoryKey"
#define BindKey(target,keyPath)         [NSString stringWithFormat:@"__binder__%@",keyPath]



static NSMutableSet *swizzledClasses() {
	static dispatch_once_t onceToken;
	static NSMutableSet *swizzledClasses = nil;
	dispatch_once(&onceToken, ^{
		swizzledClasses = [[NSMutableSet alloc] init];
	});
	
	return swizzledClasses;
}

static void swizzleDeallocIfNeeded(Class classToSwizzle) {
	@synchronized (swizzledClasses()) {
		NSString *className = NSStringFromClass(classToSwizzle);
		if ([swizzledClasses() containsObject:className]) return;
        
		SEL deallocSelector = sel_registerName("dealloc");
		SEL swizzleDeallocSelector = sel_registerName("swizzleDelloc");
		__block void (*originalDealloc)(__unsafe_unretained id, SEL) = NULL;
        
		id newDealloc = ^(__unsafe_unretained id self) {
            if(class_respondsToSelector(classToSwizzle,swizzleDeallocSelector))
                objc_msgSend(self,swizzleDeallocSelector);
			if (originalDealloc == NULL) {
				struct objc_super superInfo = {
					.receiver = self,
					.super_class = class_getSuperclass(classToSwizzle)
				};
				objc_msgSendSuper(&superInfo, deallocSelector);
			} else {
				originalDealloc(self, deallocSelector);
			}
		};
		
		IMP newDeallocIMP = imp_implementationWithBlock(newDealloc);
		
		if (!class_addMethod(classToSwizzle, deallocSelector, newDeallocIMP, "v@:")) {
			// The class already contains a method implementation.
			Method deallocMethod = class_getInstanceMethod(classToSwizzle, deallocSelector);
			
			// We need to store original implementation before setting new implementation
			// in case method is called at the time of setting.
			originalDealloc = (__typeof__(originalDealloc))method_getImplementation(deallocMethod);
			
			// We need to store original implementation again, in case it just changed.
			originalDealloc = (__typeof__(originalDealloc))method_setImplementation(deallocMethod, newDeallocIMP);
		}
        
		[swizzledClasses() addObject:className];
	}
}



@interface NSObject (SupportBinding)
- (void)setBinder:(id)binder keyPath:(NSString*)keyPath;

@end

@implementation NSObject (SupportBinding)

- (void)swizzleDelloc{
    NSMutableDictionary* bindDict = objc_getAssociatedObject(self,TMBindDictoryKey);
    [bindDict enumerateKeysAndObjectsUsingBlock:^(id key, NSArray *obj, BOOL *stop) {
        [obj enumerateObjectsUsingBlock:^(THBinder* binder, NSUInteger idx, BOOL *stop) {
            [binder stopBinding];
        }];
    }];
    objc_setAssociatedObject(self, TMBindDictoryKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (void)setBinder:(id)binder keyPath:(NSString*)keyPath{
    NSMutableDictionary* bindDict = objc_getAssociatedObject(self,TMBindDictoryKey);
    if(!bindDict){
        bindDict = [NSMutableDictionary new];
        objc_setAssociatedObject(self, TMBindDictoryKey, bindDict, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    NSString* keyName = BindKey(self, keyPath);
    id object = [bindDict valueForKey:keyName];
    
    if([object containsObject:binder]){
        return;
    }
    
    if(!object){
        object = [NSMutableArray new];
    }
    [object addObject:binder];
    [bindDict setValue:object forKey:keyName];

    swizzleDeallocIfNeeded(self.class);
}

@end



同时需要在THBinder里面加入一个方法,这样就可以讲binder保存到需要被观察的实例里面。


- (id)initForBindingFromObject:(id)fromObject keyPath:(NSString *)fromKeyPath
                      toObject:(id)toObject keyPath:(NSString *)toKeyPath
           transformationBlock:(THBinderTransformationBlock)transformationBlock
{
    if((self = [super init])) {
        __weak id wToObject = toObject;
        NSString *myToKeyPath = [toKeyPath copy];
        
        THObserverBlockWithChangeDictionary changeBlock;
        if(transformationBlock) {
            changeBlock = [^(NSDictionary *change) {
                [wToObject setValue:transformationBlock(change[NSKeyValueChangeNewKey])
                         forKeyPath:myToKeyPath];
            } copy];
        } else {
            changeBlock = [^(NSDictionary *change) {
                [wToObject setValue:change[NSKeyValueChangeNewKey]
                         forKeyPath:myToKeyPath];
            } copy];
        }
        
        _observer = [THObserver observerForObject:fromObject
                                          keyPath:fromKeyPath
                                          options:NSKeyValueObservingOptionNew
                                      changeBlock:changeBlock];
        
   <span style="color:#ff0000;">     [fromObject setBinder:self keyPath:fromKeyPath];</span>
    }
    return self;
}

在这里,我用了reactivecocoa里面的宏,来组织了这个TMBIND宏。这样使用的时候就只要这个宏就ok了。在THBinder里面会将生产的binder自动放到被观察的实例里面了。

//
//  Binder.h
//  KVODemo
//
//  Created by Tommy on 14-6-13.
//  Copyright (c) 2014年 com.taobao. All rights reserved.
//

#ifndef KVODemo_Binder_h
#define KVODemo_Binder_h

#import "EXTKeyPathCoding.h"
#import "THObserver.h"
#import "THBinder.h"


//one-way bind
#define TMBIND(_fromObject_,_fromKeyPath_,_toObject_,_toKeyPath_)     [THBinder binderFromObject:_fromObject_ keyPath:@keypath(_fromObject_, _fromKeyPath_) toObject:_toObject_ keyPath:@keypath(_toObject_,_toKeyPath_)]

#define TMBIND_WITH_TRANSFORMBLOCK(_fromObject_,_fromKeyPath_,_toObject_,_toKeyPath_,_transfromBlock_)     [THBinder binderFromObject:_fromObject_ keyPath:@keypath(_fromObject_, _fromKeyPath_) toObject:_toObject_ keyPath:@keypath(_toObject_,_toKeyPath_) transformationBlock:_transfromBlock_];








#endif





ios Bind绑定,布布扣,bubuko.com

ios Bind绑定

上一篇:ios基础-编程规范


下一篇:Cocos2d-3x:vs2012项目转为android项目需注意的地方