Texture之ASDisplayNodeInternal.h

c++容器

std::atomic<ASDisplayNodeAtomicFlags> _atomicFlags;

c++類型:atomic_uint

std::atomic_uint _displaySentinel;

static std::atomic_bool storesUnflattenedLayouts = ATOMIC_VAR_INIT(NO);//#define ATOMIC_VAR_INIT(__v) {__v}结借,沒明白ATOMIC_VAR_INIT有什么用

ASDN::RecursiveMutex __instanceLock__;

//結(jié)構(gòu)體繼承
/**
   Obj-C doesn't allow you to pass parameters to C++ ivar constructors.
   Provide a convenience to change the default from non-recursive to recursive.

   But wait! Recursive mutexes are a bad idea. Think twice before using one:

   http://www.zaval.org/resources/library/butenhof1.html
   http://www.fieryrobot.com/blog/2008/10/14/recursive-locks-will-kill-you/
   */
struct RecursiveMutex : Mutex
  {
    RecursiveMutex () : Mutex (true) {}
  };
//struct Mutex定義沒看懂乱灵,里面有pthread_mach_thread_np秃流,pthread_mutex_lock,pthread_mutex_init等使用

罕見的c++語法

std::shared_ptr<ASDisplayNodeLayout> _calculatedDisplayNodeLayout;
std::shared_ptr<ASDisplayNodeLayout> _pendingDisplayNodeLayout;
_calculatedDisplayNodeLayout = std::make_shared<ASDisplayNodeLayout>();
_pendingDisplayNodeLayout = nullptr;

初始化結(jié)構(gòu)體

struct ASDisplayNodeFlags flags = {0};
flags.isInHierarchy = NO;
  flags.displaysAsynchronously = YES;
  flags.shouldAnimateSizeChanges = YES;
  flags.implementsDrawRect = ([c respondsToSelector:@selector(drawRect:withParameters:isCancelled:isRasterizing:)] ? 1 : 0);
  flags.implementsImageDisplay = ([c respondsToSelector:@selector(displayWithParameters:isCancelled:)] ? 1 : 0);
  if (instance) {
    flags.implementsDrawParameters = ([instance respondsToSelector:@selector(drawParametersForAsyncLayer:)] ? 1 : 0);
  } else {
    flags.implementsDrawParameters = ([c instancesRespondToSelector:@selector(drawParametersForAsyncLayer:)] ? 1 : 0);
  }

c結(jié)構(gòu)體

struct ASDisplayNodeFlags {
    // public properties
    unsigned viewEverHadAGestureRecognizerAttached:1;
    unsigned layerBacked:1;
    unsigned displaysAsynchronously:1;
    unsigned rasterizesSubtree:1;
    unsigned shouldBypassEnsureDisplay:1;
    unsigned displaySuspended:1;
    unsigned shouldAnimateSizeChanges:1;
    
    // Wrapped view handling
    
    // The layer contents should not be cleared in case the node is wrapping a UIImageView.UIImageView is specifically
    // optimized for performance and does not use the usual way to provide the contents of the CALayer via the
    // CALayerDelegate method that backs the UIImageView.
    unsigned canClearContentsOfLayer:1;
    
    // Prevent calling setNeedsDisplay on a layer that backs a UIImageView. Usually calling setNeedsDisplay on a CALayer
    // triggers a recreation of the contents of layer unfortunately calling it on a CALayer that backs a UIImageView
    // it goes through the normal flow to assign the contents to a layer via the CALayerDelegate methods. Unfortunately
    // UIImageView does not do recreate the layer contents the usual way, it actually does not implement some of the
    // methods at all instead it throws away the contents of the layer and nothing will show up.
    unsigned canCallSetNeedsDisplayOfLayer:1;

    unsigned implementsDrawRect:1;
    unsigned implementsImageDisplay:1;
    unsigned implementsDrawParameters:1;

    // internal state
    unsigned isEnteringHierarchy:1;
    unsigned isExitingHierarchy:1;
    unsigned isInHierarchy:1;
    unsigned visibilityNotificationsDisabled:VISIBILITY_NOTIFICATIONS_DISABLED_BITS;
    unsigned isDeallocating:1;
  } _flags;

檢查指定類是否重寫了另一類的實(shí)例方法

BOOL ASSubclassOverridesSelector(Class superclass, Class subclass, SEL selector)
{
  if (superclass == subclass) return NO; // Even if the class implements the selector, it doesn't override itself.
  Method superclassMethod = class_getInstanceMethod(superclass, selector);
  Method subclassMethod = class_getInstanceMethod(subclass, selector);
  return (superclassMethod != subclassMethod);
}

以block的實(shí)現(xiàn)替換c類中的origSEL

IMP ASReplaceMethodWithBlock(Class c, SEL origSEL, id block)
{
  NSCParameterAssert(block);
  
  // Get original method
  Method origMethod = class_getInstanceMethod(c, origSEL);
  NSCParameterAssert(origMethod);
  
  // Convert block to IMP trampoline and replace method implementation
  IMP newIMP = imp_implementationWithBlock(block);
  
  // Try adding the method if not yet in the current class
  if (!class_addMethod(c, origSEL, newIMP, method_getTypeEncoding(origMethod))) {
    return method_setImplementation(origMethod, newIMP);
  } else {
    return method_getImplementation(origMethod);
  }
}

沒看懂

__block IMP originalLayoutSpecThatFitsIMP = ASReplaceMethodWithBlock(self, @selector(_locked_layoutElementThatFits:), ^(ASDisplayNode *_self, ASSizeRange sizeRange) {
          NSArray *oldSubnodes = _self.subnodes;
          ASLayoutSpec *layoutElement = ((ASLayoutSpec *( *)(id, SEL, ASSizeRange))originalLayoutSpecThatFitsIMP)(_self, @selector(_locked_layoutElementThatFits:), sizeRange);
          NSArray *subnodes = _self.subnodes;
          ASDisplayNodeAssert(oldSubnodes.count == subnodes.count, @"Adding or removing nodes in layoutSpecBlock or layoutSpecThatFits: is not allowed and can cause unexpected behavior.");
          for (NSInteger i = 0; i < oldSubnodes.count; i++) {
              ASDisplayNodeAssert(oldSubnodes[i] == subnodes[i], @"Adding or removing nodes in layoutSpecBlock or layoutSpecThatFits: is not allowed and can cause unexpected behavior.");
          }
          return layoutElement;
      });

setFlag(Synchronous, ![layerClass isSubclassOfClass:[_ASDisplayLayer class]]);

__unused是何用?

__unused Class initializeSelf = self;

強(qiáng)制子類重寫方法

#define ASDisplayNodeAssert(condition, desc, ...) NSAssert(condition, desc, ##__VA_ARGS__)
- (void)_staticInitialize
{
  ASDisplayNodeAssert(NO, @"_staticInitialize must be overridden");
}

神奇的語法

ASPrimitiveTraitCollection ASPrimitiveTraitCollectionMakeDefault()
{
  return (ASPrimitiveTraitCollection) {
    // Default values can be defined in here
    .userInterfaceIdiom = UIUserInterfaceIdiomUnspecified,
    .containerSize = CGSizeZero,
  };
}

檢查是否主線程

static inline BOOL ASDisplayNodeThreadIsMain()
{
  return 0 != pthread_main_np();
}

runloop相關(guān)

// Self is guaranteed to outlive the observer.  Without the high cost of a weak pointer,
    // __unsafe_unretained allows us to avoid flagging the memory cycle detector.
    __unsafe_unretained __typeof__(self) weakSelf = self;
    void (^handlerBlock) (CFRunLoopObserverRef observer, CFRunLoopActivity activity) = ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
      [weakSelf processQueue];
    };
//添加observer
    _runLoopObserver = CFRunLoopObserverCreateWithHandler(NULL, kCFRunLoopBeforeWaiting, true, 0, handlerBlock);
    CFRunLoopAddObserver(_runLoop, _runLoopObserver,  kCFRunLoopCommonModes);
    
    // It is not guaranteed that the runloop will turn if it has no scheduled work, and this causes processing of
    // the queue to stop. Attaching a custom loop source to the run loop and signal it if new work needs to be done
    CFRunLoopSourceContext sourceContext = {};
    sourceContext.perform = runLoopSourceCallback;
#if ASRunLoopQueueLoggingEnabled
    sourceContext.info = (__bridge void *)self;
#endif
    _runLoopSource = CFRunLoopSourceCreate(NULL, 0, &sourceContext);//添加source
    CFRunLoopAddSource(runloop, _runLoopSource, kCFRunLoopCommonModes);

#if ASRunLoopQueueLoggingEnabled
    _runloopQueueLoggingTimer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(checkRunLoop) userInfo:nil repeats:YES];
    [[NSRunLoop mainRunLoop] addTimer:_runloopQueueLoggingTimer forMode:NSRunLoopCommonModes];
#endif

- (void)dealloc
{
  if (CFRunLoopContainsSource(_runLoop, _runLoopSource, kCFRunLoopCommonModes)) {
    CFRunLoopRemoveSource(_runLoop, _runLoopSource, kCFRunLoopCommonModes);
  }
  CFRelease(_runLoopSource);
  _runLoopSource = nil;
  
  if (CFRunLoopObserverIsValid(_runLoopObserver)) {
    CFRunLoopObserverInvalidate(_runLoopObserver);
  }
  CFRelease(_runLoopObserver);
  _runLoopObserver = nil;
}

//手動(dòng)標(biāo)記source為待執(zhí)行并喚醒runloop
    CFRunLoopSourceSignal(_runLoopSource);
    CFRunLoopWakeUp(_runLoop);

通過CFRunLoopGetMain保障在主線程中釋放object

extern void ASPerformMainThreadDeallocation(_Nullable id object)
{
  /**
   * UIKit components must be deallocated on the main thread. We use this shared
   * run loop queue to gradually deallocate them across many turns of the main run loop.
   */
  static ASRunLoopQueue *queue;
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    queue = [[ASRunLoopQueue alloc] initWithRunLoop:CFRunLoopGetMain() retainObjects:YES handler:nil];
    queue.batchSize = 10;
  });
  if (object != nil) {
    [queue enqueue:object];
  }
}

判斷指定類是否需要在主線程中釋放

BOOL ASClassRequiresMainThreadDeallocation(Class c)
{
  if (c == [UIImage class] || c == [UIColor class]) {
    return NO;
  }
  
  if ([c isSubclassOfClass:[UIResponder class]]
      || [c isSubclassOfClass:[CALayer class]]
      || [c isSubclassOfClass:[UIGestureRecognizer class]]) {
    return YES;
  }

  const char *name = class_getName(c);
  if (strncmp(name, "UI", 2) == 0 || strncmp(name, "AV", 2) == 0 || strncmp(name, "CA", 2) == 0) {
    return YES;
  }

  return NO;
}

ASDN::MutexLocker l(instanceLock)的作用是加鎖、解鎖队橙。其內(nèi)部實(shí)現(xiàn)基本原理是在構(gòu)造函數(shù)中對instanceLock進(jìn)行了加鎖操作,在析構(gòu)函數(shù)中對instanceLock進(jìn)行了解鎖操作萨惑。

- (BOOL)shouldAnimateSizeChanges
{
  ASDN::MutexLocker l(__instanceLock__);
  return _flags.shouldAnimateSizeChanges;
}

800

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末捐康,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子咒钟,更是在濱河造成了極大的恐慌吹由,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件朱嘴,死亡現(xiàn)場離奇詭異倾鲫,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)萍嬉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進(jìn)店門乌昔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人壤追,你說我怎么就攤上這事磕道。” “怎么了行冰?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵溺蕉,是天一觀的道長。 經(jīng)常有香客問我悼做,道長疯特,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任肛走,我火速辦了婚禮漓雅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己邻吞,他們只是感情好组题,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著抱冷,像睡著了一般崔列。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上徘层,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天峻呕,我揣著相機(jī)與錄音,去河邊找鬼趣效。 笑死,一個(gè)胖子當(dāng)著我的面吹牛猪贪,可吹牛的內(nèi)容都是我干的跷敬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼热押,長吁一口氣:“原來是場噩夢啊……” “哼西傀!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起桶癣,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤拥褂,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后牙寞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體饺鹃,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年间雀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了悔详。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,427評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡惹挟,死狀恐怖茄螃,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情连锯,我是刑警寧澤归苍,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站运怖,受9級特大地震影響拼弃,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜驳规,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一肴敛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦医男、人聲如沸砸狞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽刀森。三九已至,卻和暖如春报账,著一層夾襖步出監(jiān)牢的瞬間研底,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工透罢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留榜晦,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓羽圃,卻偏偏與公主長得像乾胶,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子朽寞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 循環(huán)引用:http://ios.jobbole.com/82077/類別的作用功能:1.擴(kuò)充現(xiàn)有類的功能2.對現(xiàn)有...
    得一切從簡閱讀 503評論 0 1
  • 1.描述什么是MVC 【MVC簡介】 是一種架構(gòu)模式识窿,它是蘋果非常熱衷的一種架構(gòu)模式 M:model模型保存所有應(yīng)...
    爵笙彥閱讀 2,798評論 1 33
  • 1.項(xiàng)目經(jīng)驗(yàn) 2.基礎(chǔ)問題 3.指南認(rèn)識(shí) 4.解決思路 ios開發(fā)三大塊: 1.Oc基礎(chǔ) 2.CocoaTouch...
    陽光的大男孩兒閱讀 4,993評論 0 13
  • *面試心聲:其實(shí)這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,160評論 30 470
  • 「得到」APP「每天聽本書」欄目,5月19日更新的書單是萬維鋼解讀《無為》脑融,這本書原名為《Trying Not t...
    紫筠散思閱讀 3,526評論 0 7