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__;
//结构体继承
/**
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;
初始化结构体
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结构体
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;
检查指定类是否重写了另一类的实例方法
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的实现替换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;
强制子类重写方法
#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相关
// 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;
}
//手动标记source为待执行并唤醒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)的作用是加锁、解锁。其内部实现基本原理是在构造函数中对instanceLock进行了加锁操作,在析构函数中对instanceLock进行了解锁操作。
- (BOOL)shouldAnimateSizeChanges
{
ASDN::MutexLocker l(__instanceLock__);
return _flags.shouldAnimateSizeChanges;
}
800