当前位置: 首页 > news >正文

网站建设的进度重庆市建设工程信息网劳务资质查询

网站建设的进度,重庆市建设工程信息网劳务资质查询,如何寻找做企业网站的,网站维护员我们可以通过看通知的实现机制来了解通知中心是怎么实现对观察者的引用的。由于苹果对Foundation源码是不开源的#xff0c;我们具体就参考一下GNUStep的源码实现。GNUStep的源码地址为#xff1a;GNUStep源码GitHub下载地址, 具体源码可以进行查看。 通知的主要流程 通知全…我们可以通过看通知的实现机制来了解通知中心是怎么实现对观察者的引用的。由于苹果对Foundation源码是不开源的我们具体就参考一下GNUStep的源码实现。GNUStep的源码地址为GNUStep源码GitHub下载地址, 具体源码可以进行查看。 通知的主要流程 通知全局对象是一个名为NCTbl的结构体里头有三个重要的成员变量分别是是两张GSIMapTable表named、nameless及单链表wildcard。 named是存放传入了通知名称的通知的hash表。nameless是存放没有传入通知名称但是传入了消息发送者object的通知的hash表。wildcard是存既没有传入通知名称也没有传入消息发送者的通知的链表。 我们每次注册一个通知的时候所注册的那个通知就会按照这三种类型来对号入座放入相应的NCTbl的结构体中的GSIMapTable或wildcard。接着我们每次发送通知发送消息的时候就是先创建存储所有匹配通知的数组GSIArray按照以下流程将符合条件的通知添加到数组GSIArray中。 获取所有wildcard中符合条件的通知并添加到数组GSIArray。在nameless表中查找符合条件的通知并添加到数组GSIArray。在named表中查找符合条件的通知并添加到数组GSIArray。 最后待所有符合条件的通知都添加好之后就遍历整个GSIArray数组并依次调用performSelector:withObject处理通知消息发送。 通知原理 数据结构 _GSIMapTable映射表数据结构图如下 相关数据结构 _GSIMapTable映射表包含了nodeChunks、bukets、buketCount、chunkCount。nodeChunksnodeChunks 是一个指向 GSIMapNode 指针数组的指针。它用于管理动态分配的内存块这些内存块用于存储哈希表的节点GSIMapNode。bukets记录单链表节点指针数组的各个链表的节点数量及链表首部地址。bucketCount记录了node节点的数目。chunkCount记录单链表节点指针数组的数目。nodeCount哈希表中当前已使用的节点数量。 定义源代码 typedef struct _GSIMapBucket GSIMapBucket_t; typedef struct _GSIMapNode GSIMapNode_t;typedef GSIMapBucket_t *GSIMapBucket; typedef GSIMapNode_t *GSIMapNode;typedef struct _GSIMapTable GSIMapTable_t; typedef GSIMapTable_t *GSIMapTable;struct _GSIMapNode {GSIMapNode nextInBucket; /* Linked list of bucket. */GSIMapKey key; #if GSI_MAP_HAS_VALUEGSIMapVal value; #endif };struct _GSIMapBucket {uintptr_t nodeCount; /* Number of nodes in bucket. */GSIMapNode firstNode; /* The linked list of nodes. */ };struct _GSIMapTable {NSZone *zone;uintptr_t nodeCount; /* Number of used nodes in map. */uintptr_t bucketCount; /* Number of buckets in map. */GSIMapBucket buckets; /* Array of buckets. */GSIMapNode freeNodes; /* List of unused nodes. */uintptr_t chunkCount; /* Number of chunks in array. */GSIMapNode *nodeChunks; /* Chunks of allocated memory. */uintptr_t increment; #ifdef GSI_MAP_EXTRAGSI_MAP_EXTRA extra; #endif };具体的从映射表中添加/删除的代码如下 GS_STATIC_INLINE GSIMapBucket GSIMapPickBucket(unsigned hash, GSIMapBucket buckets, uintptr_t bucketCount) {return buckets hash % bucketCount; }GS_STATIC_INLINE GSIMapBucket GSIMapBucketForKey(GSIMapTable map, GSIMapKey key) {return GSIMapPickBucket(GSI_MAP_HASH(map, key),map-buckets, map-bucketCount); }GS_STATIC_INLINE void GSIMapLinkNodeIntoBucket(GSIMapBucket bucket, GSIMapNode node) {node-nextInBucket bucket-firstNode;bucket-firstNode node; }GS_STATIC_INLINE void GSIMapUnlinkNodeFromBucket(GSIMapBucket bucket, GSIMapNode node) {if (node bucket-firstNode){bucket-firstNode node-nextInBucket;}else{GSIMapNode tmp bucket-firstNode;while (tmp-nextInBucket ! node){tmp tmp-nextInBucket;}tmp-nextInBucket node-nextInBucket;}node-nextInBucket 0; }其实就是一个hash表结构可以以数组的形式取到每个单链表首元素再利用链表结构增删。 通知全局对象表结构如下 typedef struct NCTbl {Observation *wildcard; /* Get ALL messages*///获取所有消息GSIMapTable nameless; /* Get messages for any name.*///获取任何名称的消息GSIMapTable named; /* Getting named messages only.*///仅获取命名消息unsigned lockCount; /* Count recursive operations. *///递归运算计数NSRecursiveLock *_lock; /* Lock out other threads. *///锁定其他线程Observation *freeList;Observation **chunks;unsigned numChunks;GSIMapTable cache[CACHESIZE];unsigned short chunkIndex;unsigned short cacheIndex; } NCTable;其中数据结构中重要的是两张GSIMapTable表named、nameless及单链表wildcard named保存着传入通知名称的通知hash表nameless保存没有传入通知名称但传入了消息发送者object的hash表wildcard保存既没有通知名称又没有传入object的通知的单链表 保存含有通知名称的通知表named需要注册object对象因此该表结构体通过传入的name作为key。而它的value也是一个GSIMapTable表这个表用于存储对应的object对象的observer对象 对没有传入通知名称只传入object对象的通知表nameless而言只需要保存object与observer的对应关系因此object作为key用observer作为value。 具体的添加观察者的核心函数(block形式只是该函数的包装)大致代码如下 - (void) addObserver: (id)observerselector: (SEL)selectorname: (NSString*)nameobject: (id)object {Observation *list;Observation *o;GSIMapTable m;GSIMapNode n;//入参检查异常处理...//table加锁保持数据一致性lockNCTable(TABLE);//创建Observation对象包装相应的调用函数o obsNew(TABLE, selector, observer);//处理存在通知名称的情况if (name){//table表中获取相应name的节点n GSIMapNodeForKey(NAMED, (GSIMapKey)(id)name);if (n 0){//未找到相应的节点则创建内部GSIMapTable表以name作为key添加到talbe中m mapNew(TABLE);name [name copyWithZone: NSDefaultMallocZone()];GSIMapAddPair(NAMED, (GSIMapKey)(id)name, (GSIMapVal)(void*)m);GS_CONSUMED(name)}else{//找到则直接获取相应的内部tablem (GSIMapTable)n-value.ptr;}//内部table表中获取相应object对象作为key的节点n GSIMapNodeForSimpleKey(m, (GSIMapKey)object);if (n 0){//不存在此节点则直接添加observer对象到table中o-next ENDOBS;//单链表observer末尾指向ENDOBSGSIMapAddPair(m, (GSIMapKey)object, (GSIMapVal)o);}else{//存在此节点则获取并将obsever添加到单链表observer中list (Observation*)n-value.ptr;o-next list-next;list-next o;}}//只有观察者对象情况else if (object){//获取对应object的tablen GSIMapNodeForSimpleKey(NAMELESS, (GSIMapKey)object);if (n 0){//未找到对应object key的节点则直接添加observergnustep-base-1.25.0o-next ENDOBS;GSIMapAddPair(NAMELESS, (GSIMapKey)object, (GSIMapVal)o);}else{//找到相应的节点则直接添加到链表中list (Observation*)n-value.ptr;o-next list-next;list-next o;}}//处理即没有通知名称也没有观察者对象的情况else{//添加到单链表中o-next WILDCARD;WILDCARD o;}//解锁unlockNCTable(TABLE); }对于block形式代码如下 - (id) addObserverForName: (NSString *)name object: (id)object queue: (NSOperationQueue *)queue usingBlock: (GSNotificationBlock)block {GSNotificationObserver *observer [[GSNotificationObserver alloc] initWithQueue: queue block: block];[self addObserver: observer selector: selector(didReceiveNotification:) name: name object: object];return observer; }- (id) initWithQueue: (NSOperationQueue *)queue block: (GSNotificationBlock)block {self [super init];if (self nil)return nil;ASSIGN(_queue, queue); _block Block_copy(block);return self; }- (void) didReceiveNotification: (NSNotification *)notif {if (_queue ! nil){GSNotificationBlockOperation *op [[GSNotificationBlockOperation alloc] initWithNotification: notif block: _block];[_queue addOperation: op];}else{CALL_BLOCK(_block, notif);} }对于block形式通过创建GSNotificationObserver对象该对象会通过Block_copy拷贝block并确定通知操作队列通知的接收处理函数didReceiveNotification中是通过addOperation来实现指定操作队列处理否则直接执行block。 发送通知的核心函数大致逻辑如下 - (void) _postAndRelease: (NSNotification*)notification {//入参检查校验//创建存储所有匹配通知的数组GSIArray//加锁table避免数据一致性问题//获取所有WILDCARD中的通知并添加到数组中//查找NAMELESS表中指定对应消息发送者对象object的通知并添加到数组中//查找NAMED表中相应的通知并添加到数组中//解锁table//遍历整个数组并依次调用performSelector:withObject处理通知消息发送//解锁table并释放资源 }上面发送的重点就是获取所有匹配的通知并通过performSelector:withObject发送通知消息因此通知发送和接收通知的线程是同一个线程(block形式通过操作队列来指定队列处理)。 通知中的各个部分 NSNotification NSNotification包含了消息发送的一些信息包括name消息名称、object消息发送者、userinfo消息发送者携带的额外信息其类结构如下 interface NSNotification : NSObject NSCopying, NSCodingproperty (readonly, copy) NSNotificationName name; property (nullable, readonly, retain) id object; property (nullable, readonly, copy) NSDictionary *userInfo;- (instancetype)initWithName:(NSNotificationName)name object:(nullable id)object userInfo:(nullable NSDictionary *)userInfo API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)) NS_DESIGNATED_INITIALIZER; - (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;endinterface NSNotification (NSNotificationCreation) (instancetype)notificationWithName:(NSNotificationName)aName object:(nullable id)anObject;(instancetype)notificationWithName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;- (instancetype)init /*API_UNAVAILABLE(macos, ios, watchos, tvos)*/; /* do not invoke; not a valid initializer for this class */end可以通过实例方式构建NSNotification对象也可以通过类方式构建。- (instancetype)init这个方法是初始化方法但在 NSNotification 类中它被标记为 API_UNAVAILABLE表示不可用。因此不能直接使用此方法来初始化 NSNotification 对象。 NSNotificationCenter NSNotificationCenter消息通知中心全局单例模式(每个进程都默认有一个默认的通知中心用于进程内通信)通过如下方法获取通知中心 (NSNotificationCenter *)defaultCenter对于macOS系统每个进程都有一个默认的分布式通知中心NSDistributedNotificationCenter具体可参见:NSDistributedNotificationCenter。 具体的注册通知消息方法如下 //注册观察者 - (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSNotificationName)aName object:(nullable id)anObject; - (id NSObject)addObserverForName:(nullable NSNotificationName)name object:(nullable id)obj queue:(nullable NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));注册观察者方法提供了两种形式selector及block对于添加指定观察者对象的方式observer不能为nilblock方式会执行copy方法返回的是使用的匿名观察者对象且指定观察者处理消息的操作对象NSOperationQueue。 对于指定的消息名称name及发送者对象object都可以为空即接收所有消息及所有发送对象发送的消息若指定其中之一或者都指定则表示接收指定消息名称及发送者的消息 对于block方式指定的queue队列可为nil则默认在发送消息线程处理若指定主队列即主线程处理避免执行UI操作导致异常 注意注册观察者通知消息应避免重复注册会导致重复处理通知消息且block对持有外部对象因此需要避免引发循环引用问题。 消息发送方法如下 //发送消息 - (void)postNotification:(NSNotification *)notification; - (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject; - (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;可以通过NSNotification包装的通知消息对象发送消息也可以分别指定消息名称、发送者及携带的信息来发送且为同步执行模式需要等待所有注册的观察者处理完成该通知消息方法才会返回继续往下执行且对于block形式处理通知对象是在注册消息指定的队列中执行对于非block方式是在同一线程处理 注意消息发送类型需要与注册时类型一致即若注册观察者同时指定了消息名称及发送者则发送消息也需要同时指定消息名称及发送者否则无法接收到消息 移除观察者方法如下 //移除观察者 - (void)removeObserver:(id)observer; - (void)removeObserver:(id)observer name:(nullable NSNotificationName)aName object:(nullable id)anObject;可移除指定的观察者所有通知消息即该观察者不再接收任何消息一般用于观察者对象dealloc释放后调用但在iOS9及macos10.11之后不需要手动调用dealloc已经自动处理。 If your app targets iOS 9.0 and later or macOS 10.11 and later, you dont need to unregister an observer in its dealloc method. Otherwise, you should call this method or removeObserver:name:object: before observer or any object specified in addObserverForName:object:queue:usingBlock: or addObserver:selector:name:object:is deallocated. 翻译如下 如果你的应用目标是iOS 9.0及更高版本或macOS 10.11及更高版本你不需要在dealloc方法中注销观察者。否则您应该调用此方法或在取消分配addObserverForName:object:queue:usingBlock:或addObserver:selector:name:object:中指定的任何对象之前删除观察者name:object:方法。NSNotificationQueue NSNotificationQueue通知队列实现了通知消息的管理如消息发送时机、消息合并策略并且为先入先出方式管理消息但实际消息发送仍然是通过NSNotificationCenter通知中心完成。 interface NSNotificationQueue : NSObject property (class, readonly, strong) NSNotificationQueue *defaultQueue;- (instancetype)initWithNotificationCenter:(NSNotificationCenter *)notificationCenter NS_DESIGNATED_INITIALIZER;- (void)enqueueNotification:(NSNotification *)notification postingStyle:(NSPostingStyle)postingStyle; - (void)enqueueNotification:(NSNotification *)notification postingStyle:(NSPostingStyle)postingStyle coalesceMask:(NSNotificationCoalescing)coalesceMask forModes:(nullable NSArrayNSRunLoopMode *)modes;- (void)dequeueNotificationsMatching:(NSNotification *)notification coalesceMask:(NSUInteger)coalesceMask;可以通过defaultQueue获取当前线程绑定的通知消息队列也可以通过initWithNotificationCenter:来指定通知管理中心具体的消息管理策略如下 NSPostingStyle用于配置通知什么时候发送 NSPostASAP在当前通知调用或者计时器结束发出通知NSPostWhenIdle当runloop处于空闲时发出通知NSPostNow在合并通知完成之后立即发出通知 NSNotificationCoalescing注意这是一个NS_OPTIONS用于配置如何合并通知 NSNotificationNoCoalescing不合并通知NSNotificationCoalescingOnName按照通知名字合并通知NSNotificationCoalescingOnSender按照传入的object合并通知 对于NSNotificationQueue通知队列若不是指定NSPostNow立即发送模式则可以通过runloop实现异步发送 NSNotification与多线程 对于NSNotification与多线程官方文档说明如下 In a multithreaded application, notifications are always delivered in the thread in which the notification was posted, which may not be the same thread in which an observer registered itself. 翻译如下 在多线程应用程序中通知始终在发布通知的线程中传递该线程可能与观察者注册自身的线程不同。即是NSNotification的发送与接收处理都是在同一个线程中对于block形式则是接收处理在指定的队列中处理上面已说明这点这里重点说明下如何接收处理在其他线程处理。 For example, if an object running in a background thread is listening for notifications from the user interface, such as a window closing, you would like to receive the notifications in the background thread instead of the main thread. In these cases, you must capture the notifications as they are delivered on the default thread and redirect them to the appropriate thread. 翻译如下 例如如果在后台线程中运行的对象正在侦听来自用户界面的通知例如窗口关闭则您希望在后台线程而不是主线程中接收通知。在这些情况下您必须在通知在默认线程上传递时捕获通知并将其重定向到适当的线程。如官方说明对于处理通知线程不是主线程的如后台线程存在此处理场景并且官方也提供了具体的实施方案 一种重定向的实现思路是自定义一个通知队列(注意不是NSNotificationQueue对象而是一个数组)让这个队列去维护那些我们需要重定向的Notification。我们仍然是像平常一样去注册一个通知的观察者当Notification来了时先看看post这个Notification的线程是不是我们所期望的线程如果不是则将这个Notification存储到我们的队列中并发送一个mach信号到期望的线程中来告诉这个线程需要处理一个Notification。指定的线程在收到信号后将Notification从队列中移除并进行处理。 官方demo如下 interface MyThreadedClass: NSObject /* Threaded notification support. */ property NSMutableArray *notifications; property NSThread *notificationThread; property NSLock *notificationLock; property NSMachPort *notificationPort;- (void) setUpThreadingSupport; - (void) handleMachMessage:(void *)msg; - (void) processNotification:(NSNotification *)notification; end通知线程定义类MyThreadedClass包含了用于记录所有通知消息的通知消息队列notifications记录当前通知接收线程notificationThread多线程并发处理需要的互斥锁NSLock用于线程间通信通知处理线程处理通知消息的NSMachPort并提供了设置线程属性、处理mach消息及处理通知消息的实例方法 对于setUpThreadSupport方法如下 - (void) setUpThreadingSupport {if (self.notifications) {return;}self.notifications [[NSMutableArray alloc] init];self.notificationLock [[NSLock alloc] init];self.notificationThread [NSThread currentThread];self.notificationPort [[NSMachPort alloc] init];[self.notificationPort setDelegate:self];[[NSRunLoop currentRunLoop] addPort:self.notificationPortforMode:(NSString __bridge *)kCFRunLoopCommonModes]; }主要是初始化类属性并指定NSMachPort代理及添加至处理线程的runloop中若mach消息到达而接收线程的runloop没有运行时内核会保存此消息直到下一次runloop运行也可以通过performSelectro:inThread:withObject:waitUtilDone:modes实现不过对于子线程需要开启runloop否则该方法失效且需指定waitUtilDone参数为NO异步调用。 NSMachPortDelegate协议方法处理如下 - (void) handleMachMessage:(void *)msg {[self.notificationLock lock];while ([self.notifications count]) {NSNotification *notification [self.notifications objectAtIndex:0];[self.notifications removeObjectAtIndex:0];[self.notificationLock unlock];[self processNotification:notification];[self.notificationLock lock];};[self.notificationLock unlock]; }NSMachPort协议方法主要是检查需要处理的任何通知消息并迭代处理(防止并发发送大量端口消息导致消息丢失)处理完成后同步从消息队列中移除 通知处理方法如下 - (void)processNotification:(NSNotification *)notification {if ([NSThread currentThread] ! notificationThread) {// 将通知转发到正确的线程。[self.notificationLock lock];[self.notifications addObject:notification];[self.notificationLock unlock];[self.notificationPort sendBeforeDate:[NSDate date]components:nilfrom:nilreserved:0];}else {// Process the notification here;} }为区分NSMachPort协议方法内部调用及通知处理消息回调需要通过判定当前处理线程来处理不同的通知消息处理方式对于通知观察回调将消息添加至消息队列并发送线程间通信mach消息其实本方案的核心就是通过线程间异步通信NSMachPort来通知接收线程处理通知队列中的消息 对于接收线程需要调用如下方法启动通知消息处理 [self setupThreadingSupport]; [[NSNotificationCenter defaultCenter]addObserver:selfselector:selector(processNotification:)name:NotificationName//通知消息名称可自定义object:nil];官方也给出了此方案的问题及思考 First, all threaded notifications processed by this object must pass through the same method (processNotification:). Second, each object must provide its own implementation and communication port. A better, but more complex, implementation would generalize the behavior into either a subclass of NSNotificationCenter or a separate class that would have one notification queue for each thread and be able to deliver notifications to multiple observer objects and methods 翻译如下 首先此对象处理的所有线程通知必须通过相同的方法processNotification:。第二每个对象必须提供自己的实现和通信端口。更好但更复杂的实现将行为概括为NSNotificationCenter的一个子类或一个单独的类每个线程有一个通知队列并且能够向多个观察者对象和方法传递通知 其中指出更好地方式是自己去子类化一个NSNotficationCenter(github上有大佬实现了此方案可参考GYNotificationCenter)或者单独写一个类处理这种转发。
http://www.w-s-a.com/news/528050/

相关文章:

  • 用三权重的网站做友链有好处没企业年金怎么查询
  • 工行网站跟建设网站区别wordpress加入地图
  • 网站的风格对比信息表广告门
  • 教育网站建设毕业设计说明书门户网站模式
  • 洛阳霞光建设网站html做分模块的网站
  • 域名建议网站wordpress 伪静态html
  • 网站风格化设计方案免费模式营销案例
  • 凤翔网站建设农村建设自己的网站首页
  • 怎样用网站做单笔外贸建筑设计公司合作加盟
  • 建网站买的是什么网站开发三层结构
  • wordpress图纸管理网站2345网址导航智能主版
  • 想调用等三方网站数据该怎么做培训课程
  • 高端营销网站建设wordpress咨询
  • 网站搜索框如何做创业怎么做网站
  • 网站手机版管理链接产品推广找哪家公司
  • vuejs 可做网站吗蜘蛛互联网站建设
  • 沈阳网站备案查询17zwd一起做业网站
  • 石家庄大型公司建站广州设计网站培训学校
  • 如何让百度收录中文域名网站wordpress前台管理评论
  • 铁岭 建筑公司网站 中企动力建设佛山app开发公司
  • 网站开发用的电脑深圳专业网站建设服务
  • 内容营销价值wordpress博客优化插件
  • 最优惠的郑州网站建设淘宝网商城
  • 做封面网站企业网站优化服务商
  • 电子商务网站设计是什么蚌埠铁路建设监理公司网站
  • .name后缀的网站做房产网站多少钱
  • 手机上传网站源码网站app封装怎么做
  • 做的网站放在阿里云网站建设投标书范本
  • 做文化传播公司网站wordpress仿简书
  • 什么网站有题目做西宁网站制作哪里好