함수 프로그래밍 사용자 정의 KVO

7363 단어
앞에 쓰여있다: 오늘 주말, 외출하지 않고 이틀 동안 배운 것과 결합해서 이 데모를 두드렸는데 수준이 제한되어 있고 시계가 분출해야 한다. 물론 많은 것이 소의 어깨에 서 있고 소의 어깨가 없어서 나는 벌써 굶어 죽었다.게으른 나에게 오늘은 알차게 보냈다. 민요를 듣고, 코드를 놀고, 옆방에 텔레비전을 보는 며느리가 앉아 있었다. 하하.iOS 개발에서 애플은 우리에게 많은 리셋 메커니즘을 제공했는데 KVO(key-value-observing)가 그 중 하나이다.어떤 대상이 감청자를 등록한 후 감청된 대상이 바뀌면 감청자가 리셋 작업을 수행할 수 있도록 감청자에게 통지를 보냅니다.오늘 이 글은 주로 함수식 프로그래밍 사상을 결합시켜 KVO를 사용자 정의하기 위한 것이다.그 주요 단계는 코드와 같이 하위 클래스를 동적으로 생성하고 메시지 전달을 실현하는 것이다.

단계

  • KVO 인스턴스
  • 동적 생성 서브클래스
  • setter 방법
  • 메시지 전달
  • 먼저 People 클래스와 KVOInfoModel 클래스 People 클래스 두 가지 클래스를 생성합니다.
    People.h
     # import 
     @interface People : NSObject
     @property (nonatomic,strong) NSString *name;
     @property (nonatomic,strong) NSString *age;
     @end
    

    KVOInfoModel.h
     #import 
     typedef void(^KVOBlock) (id observer,NSString *keyPath,id newValue,id oldValue);
     @interface KVOInfoModel : NSObject
     @property (nonatomic, copy) NSString *keyPath;
     @property (nonatomic, weak) NSObject *observer;
     @property (nonatomic, copy) KVOBlock blockHandle;
     - (instancetype)initWithObserver:(NSObject *)observer keyPath:(NSString *)keyPath observerHandle:(KVOBlock)blockHandle;
     @end
    

    KVOInfoModel.m
     #import "KVOInfoModel.h"
     @implementation KVOInfoModel
     - (instancetype)initWithObserver:(NSObject *)observer keyPath:(NSString *)keyPath observerHandle:(KVOBlock)blockHandle{
         if (self = [super init]) {    
             _keyPath = keyPath;
             _observer = observer;
             _blockHandle = blockHandle;        
         } 
         return self;
     }
     @end
    

    NSObject(KVO)를 하나 더 추가합니다.h
     #import 
     #import "KVOInfoModel.h"
     @interface NSObject (KVO)
     - (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath withBlock:(KVOBlock)block;
     @end
    

    NSObject (KVO) .m
      #import "NSObject+KVO.h"
      #import 
     #import "KVOInfoModel.h"
      @implementation NSObject (KVO)
      - (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath withBlock:(KVOBlock)block{
    
    //1.   SEL  
    SEL setterSeletor = NSSelectorFromString(setterfromGetter(keyPath));
    Method setterMethod = class_getInstanceMethod(object_getClass(self), setterSeletor);
    if (!setterMethod) {
        @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@" setter " userInfo:nil];
    }
    
    //2.  
    NSString *superClassName = NSStringFromClass([self class]);
    
    Class newClas = [self creatClassFromSuperClass:superClassName];
    
    //ias swilzing  
    object_setClass(self, newClas);
    
    const char *types = method_getTypeEncoding(setterMethod);
    
    //3:setter 
    class_addMethod(newClas, setterSeletor, (IMP)KVO_Setter, types);
    
    //4; 
    KVOInfoModel *info = [[KVOInfoModel alloc] initWithObserver:observer keyPath:keyPath observerHandle:block];
    
    NSMutableArray *obserArray = objc_getAssociatedObject(self, (__bridge const void * _Nonnull)(KVOAssioKey));
    
    if (!obserArray) {
        
        obserArray = [NSMutableArray arrayWithCapacity:1];
        
        /**
          
         1: 
         2: 
         3: 
         4: 
         */
        objc_setAssociatedObject(self, (__bridge const void * _Nonnull)(KVOAssioKey), obserArray, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }  
    [obserArray addObject:info];   }
    

    pragmamark - 함수 영역

     /*  name setName: */
     static NSString * setterfromGetter(NSString * getter){
         if (getter.length <= 0) {return  nil;}  
         // name
         NSString *firstString = [[getter substringToIndex:1] uppercaseString]; // N
         NSString *leaveSTring = [getter substringFromIndex:1]; // ame   
         return [NSString stringWithFormat:@"set%@%@:",firstString,leaveSTring];
     }
     /*  setName name */
     static NSString *getterfromSetter(NSString * setter){  
         if (setter.length <= 0 || ![setter hasPrefix:@"set"] || ![setter hasSuffix:@":"]) { return nil;}  
         //setName:  ===>> Name:  ====> Name ==> name  
         NSRange range = NSMakeRange(3, setter.length-4);
         NSString *getter = [setter substringWithRange:range];
         NSString *firstString = [[getter substringToIndex:1] lowercaseString]; //n
         getter = [getter stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:firstString]; 
         return getter;
     }
     /*  */
     static Class KVC_Class(id self){
         return class_getSuperclass(object_getClass(self));
     }
     - (Class)creatClassFromSuperClass:(NSString *)superName{   
         Class superClass = NSClassFromString(superName);
       /**
      
     1: 
     2: 
     3: 
     */
    // NSKVONotifiying_   ===>>> KCKVC_
    NSString *newClassName = [KVOPre stringByAppendingString:superName];
    Class newClass = NSClassFromString(newClassName);
    if (newClass) {
        return newClass;
    }
    
    newClass = objc_allocateClassPair(superClass, newClassName.UTF8String, 0);
    
    // Class
    Method classMethod = class_getClassMethod(superClass, @selector(class));
    
    const char *type = method_getTypeEncoding(classMethod);
    /**
      
     1: 
     2: 
     3:IMP   
     4: 
     */
    class_addMethod(newClass, @selector(class), (IMP)KVC_Class, type);
    // 
    objc_registerClassPair(newClass);   
    return newClass;
    }
      static void KVO_Setter(id self,SEL _cmd,id newValue){
    
    // 
    //_cmd ===
    
    
    NSString *setterName = NSStringFromSelector(_cmd);
    NSString *getterName = getterfromSetter(setterName);
    
    id oldValue = [self valueForKey:getterName];
    
    [self willChangeValueForKey:getterName];
    
    // 
    
    void(*KCMsgSend)(void *,SEL,id) = (void *)objc_msgSendSuper;
    
    struct objc_super kcSuperStruct = {
        .receiver = self,
        .super_class = class_getSuperclass(object_getClass(self))
    };
    
    KCMsgSend(&kcSuperStruct,_cmd,newValue);
    
    
    [self didChangeValueForKey:getterName];
    
    
    
    NSMutableArray *obserArray = objc_getAssociatedObject(self, (__bridge const void * _Nonnull)(KVOAssioKey));
    
    for (KVOInfoModel *info in obserArray) {
        dispatch_async(dispatch_queue_create(0, 0), ^{
            info.blockHandle(self, info.keyPath, newValue, oldValue);
        });
    }
    
    
    
      }
    
      @end
    

    VC 콜백 KVO
      #import "ViewController.h"
      #import "People.h"
      #import "NSObject+KVO.h"
      @interface ViewController ()
    
      @property (nonatomic,strong) People *people;
    
      @end
    
      @implementation ViewController
    
      - (void)viewDidLoad {
          [super viewDidLoad];
    
          self.people = [[People alloc] init];
    
          [self.people addObserver:self forKeyPath:@"name" withBlock:^(id observer, NSString *keyPath, id newValue, id oldValue) {
              NSLog(@"%@==%@",newValue,oldValue);
    
          }];
          [self.people addObserver:self forKeyPath:@"age" withBlock:^(id observer, NSString *keyPath, id newValue, id oldValue) {
              NSLog(@"%@==%@",newValue,oldValue);
        
          }];
          self.people.name = @"hanhan";
          self.people.age = @"100";
      }
      - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    
          self.people.name = [NSString stringWithFormat:@"%@+",self.people.name];
          self.people.age = [NSString stringWithFormat:@"%@+",self.people.age];
      }
    
      - (void)dealloc{
          [self.people removeObserver:self forKeyPath:@"name"];
      }
    

    이렇게 하면 사용자 정의 KVO를 실현할 수 있다. 면접에서 사용할 때 절대 6의 비교를 이루었고 프로젝트에 구체적으로 사용되지 않았다. 앞으로 계속 공부하고 자신을 계속 향상시킬 것이다.END

    좋은 웹페이지 즐겨찾기