ios Bind绑定

来源:互联网 发布:sql中查询重复的数据 编辑:程序博客网 时间:2024/05/22 08:22

   不管是用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





0 0
原创粉丝点击