YYModel學習筆記

kim_jin發表於2017-12-26

1.Block有3種型別:NSGlobalBlock, NSMallocBlockNSStackBlock三種,父類為NSBlock.

  • NSGlobalBlock位於全域性區,在不捕獲外部引數或者全域性變數的情況下為此型別. retain, copyrelease無效
  • NSMallocBlock位於堆區,從棧區複製過來的。retain, release無效
  • NSStackBlock位於棧區,引用外部變數時為此類。在ARC下,一般ARC會自動將block從堆區copy到棧區。支援retainrelease

http://ibloodline.com/articles/2016/01/20/memory2-block.html

在ARC下進行列印的話,只會看到NSGlobalBlockNSMallocStack兩種型別的block,原因是因為賦值給strong物件時會自動進行copy

複製程式碼

int i=0; NSLog(@"%@", ^{ NSLog(@"stack block here, i=%d", i); }); //<NSStackBlock: 0x7fff592eacf8> void (^block)()=^{ NSLog(@"stack block here, i=%d", i); }; NSLog(@"%@",block);

複製程式碼

使用__block修飾的變數與全域性變數在被block內部使用時,block是根據變數的地址來獲取值,而區域性變數的話則是copy一次後進行使用:

      int i = 0;
      void (^block1)() = ^{
          NSLog(@"Block i: %p", &i);
          NSLog(@"Block i: %d", i);
      };
      
      static int k = 1;
      void (^block2)() = ^{
          NSLog(@"Block k: %p", &k);
          NSLog(@"Block k: %d", k);
      };
      
      __block int j = 1;
      void (^block3)() = ^{
          NSLog(@"Block j: %p", &j);
          NSLog(@"Block j: %d", j);
      };
      NSLog(@"i: %p", &i);
      i++;
      block1();
      NSLog(@"j: %p", &j);
      j++;
      block3();
      NSLog(@"k: %p", &k);
      k++;
      block2();

複製程式碼

輸出如下:

2017-06-06 10:39:11.680 LearnYYKit[1694:98529] i: 0x7fff5f9b159c
2017-06-06 10:39:11.681 LearnYYKit[1694:98529] Block i: 0x60000004b960
2017-06-06 10:39:11.682 LearnYYKit[1694:98529] Block i: 0
2017-06-06 10:39:11.682 LearnYYKit[1694:98529] j: 0x60000002cc78
2017-06-06 10:39:11.682 LearnYYKit[1694:98529] Block j: 0x60000002cc78
2017-06-06 10:39:11.682 LearnYYKit[1694:98529] Block j: 2
2017-06-06 10:39:11.683 LearnYYKit[1694:98529] k: 0x100251370
2017-06-06 10:39:11.683 LearnYYKit[1694:98529] Block k: 0x100251370
2017-06-06 10:39:11.683 LearnYYKit[1694:98529] Block k: 2
複製程式碼

好像有點跑題,不過剛好看到從獲取NSBlock類的方法時順帶複習一下Block的知識。。。。

2.YYEncodingType分成三種型別:

  • 型別: unknown, void, bool...
  • 修飾符: in, out, const...
  • 屬性修飾符: readonly, nonatomic, weak, ...

3.YYClassInfo的類:

YYClassIvarInfo YYClassMethodInfo YYClassPropertyInfo YYClassInfo
Ivar ivar Method method objc_property_t property Class cls
NSString *name NSString *name NSString *name Class superCls
ptrdiff_t offset(ptrdiff_t表示的是兩個指標之間的差) SEL sel YYEncodingType type Class metaCls
NSString *typeEncoding IMP imp NSString *ivarName BOOL isMeta
NSString *typeEncoding Class cls NSString *name
NSString *returnTypeEncoding NSString *protocols YYClassInfo superClassInfo
NSString *argumentTypeEncodings SEL getter NSDictionary * ivarInfos
SEL setter NSDictionary *methodInfos
NSDictionary *propertyInfos

通過這幾個類,我們也能看出在OC中,一個物件在runtime時的結構,實際上YYModel的這幾個類就是根據isa指標的指向來構造完成。

4.對於property的編碼中,物件的型別的編碼是根據@""xxx""來判斷,protocol是根據@""""來判斷: e.g:

// 利用NSLog輸出的話:
@“Student”
@"<MyProtocol>"
複製程式碼

5.獲取Meta類時,使用object_getClass()這個函式來獲取。因為object_getClass()獲取的是isa的指向 6.在YYClassInfo中,有一個classInfoWithClass:的初始化的類函式,其中有兩個CFMutableDictionaryRef的物件,用於快取類以及元類的資訊。另外,在對這兩個物件的讀寫過程中,使用了GCD的訊號量來進行鎖操作。

7.dispatch_semaphore_wait()會將訊號量減1,當訊號量<=0的時候,當前佇列會進入等待狀態,直到呼叫dispatch_semaphore_signal()函式將訊號量增加到大於0,再繼續操作。一般用法:

dispatch_semaphore_t dsema = dispatch_semaphore_create(1);
dispatch_semaphore_wait(dsema);
// 只允許單個執行緒操作的程式碼
dispatch_semaphore_signal(dsema);
複製程式碼

8.YYValueForKeyPath用於從NSDictionary中取值,可用於多層巢狀的情況 9._YYModelPropertyMeta: 物件中的屬性

@interface _YYModelPropertyMeta : NSObject {
  @package
  NSString *_name;             ///< s屬性名稱
  YYEncodingType _type;        ///< 型別
  YYEncodingNSType _nsType;    ///< 在Foundation中的型別
  BOOL _isCNumber;             ///< 是否為C的基本型別
  Class _cls;                  ///< 所屬的類
  Class _genericCls;           ///< container's generic class, or nil if threr's no generic class
  SEL _getter;                 ///< getter方法
  SEL _setter;                 ///< setter方法
  BOOL _isKVCCompatible;       ///< 是否能使用KVC訪問
  BOOL _isStructAvailableForKeyedArchiver; ///< 能否進行歸檔解檔
  BOOL _hasCustomClassFromDictionary; ///< 是否實現了+modelCustomClassForDictionary:方法
  
  NSString *_mappedToKey;      ///< 所對應的key
  NSArray *_mappedToKeyPath;   ///< 對應的keyPath
  NSArray *_mappedToKeyArray;  ///< key或者keyPath
  YYClassPropertyInfo *_info;  ///< 屬性Info
  _YYModelPropertyMeta *_next; ///< 指向下一個共享同個key的meta物件
}
複製程式碼

10.在使用NSKeyedUnarchiver解檔的時候,對於結構體來說, 只支援下面幾種NSValue的類:CGSize, CGRect, CGPoint, UIOffset, UIEdgeInset, CGAffineTransform 11._YYModelMeta例項:

@interface _YYModelMeta : NSObject {
  @package
  YYClassInfo *_classInfo;
  /// Key:對映的key或者keyPath, Value:_YYModelPropertyMeta.
  NSDictionary *_mapper;
  /// Model所有的property meta
  NSArray *_allPropertyMetas;
  /// 給定keypath的property meta
  NSArray *_keyPathPropertyMetas;
  /// 給定多個keys對應的property meta
  NSArray *_multiKeysPropertyMetas;
  /// _mapper的數量
  NSUInteger _keyMappedCount;
  /// Model的類.
  YYEncodingNSType _nsType;
  
  BOOL _hasCustomWillTransformFromDictionary;
  BOOL _hasCustomTransformFromDictionary;
  BOOL _hasCustomTransformToDictionary;
  BOOL _hasCustomClassFromDictionary;
}
複製程式碼
  1. ((bool (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter)如果沒理解錯的話,應該是將objc_msgSend這個函式強制轉換為bool (*) (id, SEL)型別