NiiOS-iOS复习及在学习进度更新

仓库地址

本次更新日期:2020年12月11日

NiiOS
(一) 简介 & 规划

i、「目前主要做iOS客户端开发」一直没有好好沉淀记录下自己学习东西;这里把目前主要做的iOS端常用知识点总结下,便于后续开发拿来直接用;
ii、后续会陆续贴出完整的复习笔记,有需要联系作者;


(二十二) iOS RunLoop(三)
RunLoop-3-iOS - 深入理解 RunLoop
	3. RunLoop的实际应用举例
		- [x] 3.1 AFNetworking
		- [x] 3.1 AsyncDisplayKit
	2. 苹果用RunLoop实现的功能
		2.1 AutoreleasePool
			- [x] App启动后,苹果在主线程 RunLoop 里注册了两个 Observer,其回调都是 _wrapRunLoopWithAutoreleasePoolHandler()。
			- [x] 第一个 Observer 监视的事件是 Entry(即将进入Loop),其回调内会调用 _objc_autoreleasePoolPush() 创建自动释放池。其 order 是-2147483647,优先级最高,保证创建释放池发生在其他所有回调之前。
			- [x] 第二个 Observer 监视了两个事件: BeforeWaiting(准备进入休眠) 时调用_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 释放旧的池并创建新池;Exit(即将退出Loop) 时调用 _objc_autoreleasePoolPop() 来释放自动释放池。这个 Observer 的 order 是 2147483647,优先级最低,保证其释放池子发生在其他所有回调之后。
		2.2 事件响应
			- [x] 苹果注册了一个 Source1 (基于 mach port 的) 用来接收系统事件,其回调函数为 __IOHIDEventSystemClientQueueCallback()。
		1.3 手势识别
			- [x] 苹果注册了一个 Observer 监测 BeforeWaiting (Loop即将进入休眠) 事件,这个Observer的回调函数是_UIGestureRecognizerUpdateObserver(),其内部会获取所有刚被标记为待处理的 GestureRecognizer,并执行GestureRecognizer的回调。
			- [x] 当有 UIGestureRecognizer 的变化(创建/销毁/状态改变)时,这个回调都会进行相应处理。
		1.4 界面更新
			- [x] 苹果注册了一个 Observer 监听 BeforeWaiting(即将进入休眠) 和 Exit (即将退出Loop) 事件,回调去执行一个很长的函数:_ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv()。这个函数里会遍历所有待处理的 UIView/CAlayer 以执行实际的绘制和调整,并更新 UI 界面。
		1.5 定时器
			- [x] NSTimer 其实就是 CFRunLoopTimerRef,他们之间是 toll-free bridged 的。一个 NSTimer 注册到 RunLoop 后,RunLoop 会为其重复的时间点注册好事件。
		1.6 PerformSelector
			- [x] 当调用 NSObject 的 performSelecter:afterDelay: 后,实际上其内部会创建一个 Timer 并添加到当前线程的 RunLoop 中。所以如果当前线程没有 RunLoop,则这个方法会失效。
			- [x] 当调用 performSelector:onThread: 时,实际上其会创建一个 Timer 加到对应的线程去,同样的,如果对应线程没有 RunLoop 该方法也会失效。
		1.7 关于GCD
			- [x] 实际上 RunLoop 底层也会用到 GCD 的东西,NSTimer 是用了 XNU 内核的 mk_timer,但同时 GCD 提供的某些接口也用到了 RunLoop, 例如 dispatch_async()。当调用 dispatch_async(dispatch_get_main_queue(), block) 时,libDispatch 会向主线程的 RunLoop 发送消息,RunLoop会被唤醒,并从消息中取得这个 block,并在回调 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__() 里执行这个 block。但这个逻辑仅限于 dispatch 到主线程,dispatch 到其他线程仍然是由 libDispatch 处理的。
		1.8 关于网络请求
			iOS 中,关于网络请求的接口自下至上有如下几层:
				- [x] CFSocket 是最底层的接口,只负责socket通信。
				- [x] CFNetwork 是基于CFSocket等接口的上层封装,ASIHttpRequest工作与这一层。
				- [x] NSURLConnection 是基于CFNetwork的更高层的封装,提供面向对象的接口,AFNetworking工作于这一层。
				- [x] NSURLSession 是iOS7中新增的接口,表面上是和 NSURLConnection 并列的,但底层仍然用到了 NSURLConnection 的部分功能 (比如 com.apple.NSURLConnectionLoader 线程),AFNetworking2 和 Alamofire 工作于这一层。
				主要介绍下 NSURLConnection 的工作过程
					- [x] 通常使用 NSURLConnection 时,你会传入一个 Delegate,当调用了 [connection start] 后,这个 Delegate 就会不停收到事件回调。实际上,start 这个函数的内部会会获取 CurrentRunLoop,然后在其中的 DefaultMode 添加了4个 Source0 (即需要手动触发的Source)。CFMultiplexerSource 是负责各种 Delegate 回调的,CFHTTPCookieStorage 是处理各种 Cookie 的。
					- [x] 当开始网络传输时,我们可以看到 NSURLConnection 创建了两个新线程:com.apple.NSURLConnectionLoader 和 com.apple.CFSocket.private。其中 CFSocket 线程是处理底层 socket 连接的。NSURLConnectionLoader 这个线程内部会使用 RunLoop 来接收底层 socket 的事件,并通过之前添加的 Source0 通知到上层的 Delegate。
					- [x] NSURLConnectionLoader 中的 RunLoop 通过一些基于 mach port 的 Source 接收来自底层 CFSocket 的通知。当收到通知后,其会在合适的时机向 CFMultiplexerSource 等 Source0 发送通知,同时唤醒 Delegate 线程的 RunLoop 来让其处理这些通知。CFMultiplexerSource 会在 Delegate 线程的 RunLoop 对 Delegate 执行实际的回调。
	1.RunLoop 的概念
		- [x] RunLoop 实际上就是一个对象,这个对象管理了其需要处理的事件和消息,并提供了一个入口函数来执行上面的Event Loop 的逻辑。线程执行了这个函数之后,就会一直处于这个函数内部"接受消息->等待->处理"的循环中,直到这个循环结束(比如传入 quit的消息),函数返回。
		1.1 RunLoop 与线程的关系
			- [x] 线程和RunLoop 之间是一一对应的,其关系保存在一个全局的 Dictionary 里。线程刚创建时并没有 RunLoop,如果你不主动获取,那么它一直都不会有。RunLoop 的创建是发生在第一次获取时,RunLoop 的销毁时发生在线程结束时。你只能在一个线程的内部获取其 RunLoop(主线程除外)
		- [x] 1.2 RunLoop 对外的接口
		- [x] 1.3 RunLoop 的 Mode
		1.4 RunLoop的内部逻辑
			- [x] 实际上RunLoop就是这样一个函数,其内部是一个do-while循环。当你调用CFRunLoopRun()时,线程会一直停留在这个循环里,直到超时或被手动停止,该函数才会返回。
		1.5 RunLoop的底层实现
			OSX/iOS的系统架构
				- [x] 应用层:包括用户能接触到的图形应用,例如Spotlight,Aqua,SpringBoard等
				- [x] 应用框架层:开发人员接触到的Cocoa等框架
				- [x] 核心框架层:包括各种核心框架,OpenGL等内容
				Darwin:即操作系统的核心,包括系统内核,驱动,Shell等内容,这一层是开源的。其所有源码都可以在opensource.apple.com中找到
					- [x] 为了实现消息的发送和接收,mach_msg() 函数实际上是调用了一个 Mach 陷阱 (trap),即函数mach_msg_trap(),陷阱这个概念在 Mach 中等同于系统调用。当你在用户态调用 mach_msg_trap() 时会触发陷阱机制,切换到内核态;内核态中内核实现的 mach_msg() 函数会完成实际的工作
					- [x] RunLoop 的核心就是一个 mach_msg() (见上面代码的第7步),RunLoop 调用这个函数去接收消息,如果没有别人发送 port 消息过来,内核会将线程置于等待状态。例如你在模拟器里跑起一个 iOS 的 App,然后在 App 静止时点击暂停,你会看到主线程调用栈是停留在 mach_msg_trap() 这个地方。

(二十一) iOS RunLoop(二)
RunLoop-2-iOS 多线程:RunLoop详细总结
	4. RunLoop 实战应用
		- [x] 4.1 NSTimer 的使用(详细见2.3CFRunLoopTimerRef)
		- [x] 4.2ImageView 推迟显示
		4.3 后台常驻线程(很常用)
			- [x] 我们再开发应用程序的过程中,如果后台操作特别频繁,经常会在子线程做一些耗时操作(下载文件,后台播放音乐等),我们最好能让这条线程永远常驻内存。
			做法如下:
				- [x] 添加一条用于常驻内存的强引用的子线程,在该线程的 RunLoop 下添加一个 Source,开启 RunLoop。
			具体操作如下:
				- [x] 1.添加一条强引用的 thread 线程属性。
				- [x] 2.创建线程平启动方法
	3. RunLoop 原理
		在每次运行开启 RunLoop 的时候,所在线程的 RunLoop 会自动处理之前未处理的事件,并且通知相关的观察者。
		RunLoop 的运行逻辑
			- [x] 1.通知观察者 RunLoop 已经启动
			- [x] 2.通知观察者即将要开始的定时器
			- [x] 3.通知观察者任何即将启动的非基于端口的源
			- [x] 4.启动任何准备好的非基于端口的源
			- [x] 5.如果基于端口的源准备好并处于等待状态,立即启动,并进入步骤9
			- [x] 6.通知观察者线程进入休眠状态
			7.将线程置于休眠,知道任一下面的事件发生:
				- [x] 某一事件到达基于端口的源
				- [x] 定时器启动
				- [x] RunLoop 设置的时间已经超时
				- [x] RunLoop 被显示唤醒
			- [x] 8.通知观察者线程将被唤醒
			9.处理未处理的事件
				- [x] 如果用户定义的定时器启动,处理定时器事件并重启 RunLoop,进入步骤2
				- [x] 如果输入源启动,传递相应的消息
				- [x] 如果 RunLoop 被显示唤醒而且时间还没超时,重启 RunLoop,进入步骤2
			- [x] 10.通知观察者 RunLoop 结束
	2. RunLoop 相关类
		- [x] 1.CFRunLoopRef:代表 RunLoop 的对象
		- [x] 2.CFRunLoopModeRef:RunLoop 的运行模式
		3.CFRunLoopSourceRef:就是上图提到的输入源、事件源
			- [x] input sources(输入源)
			- [x] Timer sources(定时源)
		- [x] 4.CFRunLoopTimerRef:就是上图提到的定时源
		- [x] 5.CFRunLoopObserverRef:观察者,可以监听 RunLoop 的状态改变
		2.1 CFRunLoopRef
			Core Foundation
				- [x] CFRunLoopGetCurrent() 获得当前线程的 RunLoop 对象
				- [x] CFRunLoopGetMain() 获得主线程的 RunLoop 对象
			Foundation
				- [x] [NSRunLoop currentRunLoop] 获得当前线程的RunLoop对象
				- [x] [NSRunLoop mainRunLoop] 获得主线程的RunLoop对象
		2.2 CFRunLoopModeRef
			- [x] kCFRunLoopDefaultMode App 的默认运行模式,通常主线程是在这个运行模式下运行的
			- [x] UITrackingRunLoopMode 跟踪用户交互事件(用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响)
			- [x] UIInitializationRunLoopMode 在刚启动 App 时首次进入的第一个 Mode,启动完成后就不再使用
			- [x] GSEventReceiveRunLoopMode 接受系统内部事件,通常用不到
			- [x] kCFRunLoopCommonModes 伪模式,不是一种真正的运行模式
			- [x] 其中kCFRunLoopDefaultMode,UITrackingRunLoopMode,kCFRunLoopCommonModes是我们开发中需要用到的模式。
		2.3 CFRunLoopTimerRef
			- [x] CFRunLoopTimerRef是定时源,理解即为基于时间的触发器,可以将其理解为定时器。
			然道我们就不能在这两种模式都让NSTimer 都能正常工作吗?
				- [x] 那么哪些模式被标记上了 Common Modes 呢?
				- [x] 当然可以,这就用到了我们之前说的伪模式 (kCFRunLoopCommonModes),这其实不是一种真实的模式,而是一种标记模式,意思就是可以在打上Common Modes 标记的模式下运行。
				- [x] NSDefaultRunLoopMode 和 UITrackingRunLoopMode
		2.4 CFRunLoopSourceRef
			CFRunLoopSourceRef是事件源,(上图中有提到过),CFRunLoopSourceRef有两种分类方法。
				第一种按照官方文档来分类(就像 RunLoop 模型图中的那样)
					- [x] Port-Based Sources(基于端口)
					- [x] Custom Input Source(自定义)
					- [x] Cocoa Perform Selector Sources
				第二种按照函数调用栈来分类:
					- [x] Source0:非基于 Port
					- [x] Source1:基于 Port,通过内核和其他线程通信,接收,分发系统事件
				总结:这两种分类方式其实没有什么区别,只不过第一种是通过官方理论来分类,第二种是在实际应用中通过调用函数来分类。
		2.5 CFRunLoopObserverRef
			- [x] CFRunLoopObserverRef是观察者,用来监听 RunLoop 的状态改变
	1. RunLoop 简介
		1.1 什么是 RunLoop?
			- [x] 根据字面意思:Run 表示运行,Loop 表示循环,结合在一起就是运行的循环。
			- [x] RunLoop 实际上是一个对象,这个对象在循环中用来处理程序运行过程中出现的各种事件(比如触摸事件,UI 刷新事件,定时器事件,selector 事件),从而保持程序的持续运行;而且在没有事件处理的时候,会进入睡眠模式,从而节省 CPU 资源,提高程序性能。
		1.2 RunLoop 和线程
			- [x] RunLoop 和线程息息相关,我们知道线程的作用是用来执行特定的一个或多个任务,但是在默认情况下,线程执行完之后就会退出,就不能再执行任务了。这时我们就需要采用一种方式来让线程能够处理任务,并不退出。所以就有了 RunLoop。
			- [x] 1.一条线程对应一个 RunLoop 对象,每条线程都有唯一一个与之对应的 RunLoop 对象。
			- [x] 2.我们只能在当前线程中操作当前线程的 RunLoop,而不能去操作其他线程的 RunLoop。
			- [x] 3.RunLoop 对象在第一次获取 RunLoop 时创建,销毁则是在线程结束的时候。
			- [x] 4.主线程的 RunLoop 对象,系统自动帮我们创建好了(原理如下)。而子线程的 RunLoop 对象需要我们主动创建.
		1.3 默认情况下主线程的 RunLoop 原理
			- [x] 其中UIApplicationMain函数内部帮我们开启了主线程RunLoop,UIApplicationMain内部拥有一个无线循环的代码
			- [x] RunLoop 就是线程中的一个循环,RunLoop 在循环中会不断检测,通过input sources(输入源)和Timer sources(定时源)两种来源等待接受事件;然后对接受到的事件通知线程进行处理,并在没有事件的时候进行休息。

(二十) iOS RunLoop
Runloop
	RunLoop的应用
		- [x] 常驻线程
		NSTimer
			- [x] 1. 定时器的使用
			- [x] 2. 滑动时失效
			- [x] 3. 不准时
		- [x] AutoreleasePool
		- [x] 事件响应
		- [x] 手势识别
		- [x] 界面更新
		PerformSelecter
			// 1.和RunLoop不相干,底层直接调用objc_sendMsg方法
				- [x] (id)performSelector:(SEL)aSelector withObject:(id)object;
			// 2. 和RunLoop相关,封装成Source0事件,依赖于RunLoop,若线程无对应的RunLoop,会调用objc_sendMsg执行
				- [x] (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
			// 3. 和RunLoop相关,封装成Timers事件
				- [x] (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;
		关于 GCD
			- [x] 在 RunLoop 的源代码中可以看到用到了 GCD 的相关内容,但是 RunLoop 本身和 GCD 并没有直接的关系。
	RunLoop中的Mode
		- [x] 一个RunLoop包含若干个Mode,每个Mode又包含若干个 Source/Timer/Observer。这句话真的是点晴之笔,一句话就把5个相关类的关系说的一清二楚。
		- [x] 一个CFRunLoopModeRef对象有一个name,若干source0,source1,timer,observer和port,可以看出事件都是由mode在管理,而RunLoop管理着Mode。
		__CFRunLoopMode的五种运行模式(系统默认注册的五个Mode)
			- [x] 1. kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行
			- [x] 2. UITrackingRunLoopMode:界面跟踪Mode,用于ScrollView追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
			- [x] 3. UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用,会切换到kCFRunLoopDefaultMode
			- [x] 4. GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到
			- [x] 5. kCFRunLoopCommonModes: 这是一个占位用的Mode,作为标记kCFRunLoopDefaultMode和UITrackingRunLoopMode用,并不是一种真正的Mode 
		CFRunLoopSourceRef
			- [x] Source0 只包含了一个回调(函数指针),它并不能主动触发事件。使用时,你需要先调用 CFRunLoopSourceSignal (source),将这个 Source 标记为待处理,然后手动调用 CFRunLoopWakeUp (runloop) 来唤醒 RunLoop,让其处理这个事件。
			- [x] Source1 包含了一个 mach_port 和一个回调(函数指针),被用于通过内核和其他线程相互发送消息。这种Source 能主动唤醒 RunLoop 的线程,其原理在下面会讲到。
		CFRunLoopTimerRef
			- [x] 是基于时间的触发器
			- [x] CFRunLoopTimerRef 是基于时间的触发器,它和 NSTimer 是 toll-free bridged 的,可以混用。其包含一个时间长度和一个回调(函数指针)。当其加入到 RunLoop 时,RunLoop 会注册对应的时间点,当时间点到时,RunLoop 会被唤醒以执行那个回调。
		CFRunLoopObserverRef
			- [x] CFRunLoopObserverRef 是观察者,每个 Observer 都包含了一个回调(函数指针),当 RunLoop 的状态发生变化时,观察者就能通过回调接受到这个变化。
	RunLoop的相关类之间关系
		RunLoop相关的类有5个
			- [x] 1.CFRunLoopRef
			- [x] 2.CFRunLoopModeRef
			- [x] 3.CFRunLoopSourceRef
			- [x] 4.CFRunLoopTimerRef
			- [x] 5.CFRunLoopObserverRef
		那么每个类都是什么呢?
			- [x] 1.第一个类我在前面已经剖析过了,它就是RunLoop对象所属于的类
			- [x] 2.CFRunLoopModeRef 是 RunLoop 当前的一个运行模式,什么是运行模式呢?我会在RunLoop和Mode这一节仔细讲解
			- [x] 3.CFRunLoopSourceRef和CFRunLoopTimerRef是RunLoop处理的消息类型
			- [x] 4.CFRunLoopObserverRef监听RunLoop运行状态的一个类
		各个类之间的关系
			- [x] 1.一个RunLoop包含若干个Mode,每个Mode又包含若干个Source/Timer/Observer。
			- [x] 2.每次调用 RunLoop的主函数时,只能指定其中一个 Mode,这个Mode被称作CurrentMode。
			- [x] 3.如果需要切换 Mode,只能退出Loop,再重新指定一个Mode进入。这样做主要是为了分隔开不同组的 Source/Timer/Observer,让其互不影响。
			- [x] 4.如果一个 mode中一个Source/Timer/Observer 都没有,则RunLoop会直接退出,不进入循环。
		各个类的作用
			- [x] 1.CFRunLoopRef是一个CFRunLoop结构体的指针,所以说它的职责就是CFRunLoop的职责,运行循环,处理事件,保持运行
			- [x] 2.CFRunLoopModeRef运行模式,模式下对应多个处理源,具体有哪些模式我会在RunLoop和Mode这一节仔细讲解
			3.CFRunLoopSourceRef是事件产生的地方。Source有两个版本:Source0 和 Source1。
				- [x] 1.Source0触摸事件处理
				- [x] 2.Source1基于Port的线程见通信
			- [x] 4.CFRunLoopTimerRefNSTimer的运用
			- [x] 5.CFRunLoopObserverRef用于监听RunLoop的状态,UI刷新,自动释放池
	RunLoop和线程
		- [x] 1.RunLoop是基于线程来管理的,它们一一对应,共同存储在一个全局区的runLoopDict中,线程是key,RunLoop是value。
		- [x] 2.RunLoop的创建:主线程所对应RunLoop在程序一启动创建主线程的时候系统就会自动为我们创建好,而子线程所对应的RunLoop并不是在子线程创建出来的时候就创建好的,而是在我们获取该子线程所对应的RunLoop时才创建出来的,换句话说,如果你不获取一个子线程的RunLoop,那么它的RunLoop就永远不会被创建。
		- [x] 3.RunLoop的获取:我们可以通过一个指定的线程从runLoopDict中获取它所对应的RunLoop。
		- [x] 4.RunLoop的销毁:系统在创建RunLoop的时候,会注册一个回调,确保线程在销毁的同时,也销毁掉其对应的RunLoop。
	CFRunLoopRef对象源码剖析
		- [x] NSRunLoop对象是基于CFRunLoopRef的,并且CFRunLoopRef是基于c语言的,线程安全
	RunLoop对象的获取
		CoreFoundation
			CFRunLoopRef对象
				- [x] CFRunLoopGetCurrent(); // 获得当前线程的RunLoop对象
				- [x] CFRunLoopGetMain();   // 获得主线程的RunLoop对象
		Fundation框架 (基于CFRunLoopRef的封装)
			NSRunLoop对象
				- [x] [NSRunLoop currentRunLoop]; // 获得当前线程的RunLoop对象
				- [x] [NSRunLoop mainRunLoop];   // 获得主线程的RunLoop对象
	RunLoop在何处开启?
		- [x] 在UIApplicationMain函数中,开启了一个和主线程相关的RunLoop,导致UIApplicationMain不会返回,一直在运行中,也就保证了程序的持续运行
	RunLoop的作用
		1.保持程序持续运行
			- [x] 程序一启动就会开一个主线程,主线程一开起来就会跑一个主线程对应的RunLoop,RunLoop保证主线程不会被销毁,也就保证了程序的持续运行
		2.处理App中的各种事件
			- [x] 1.定时器(Timer)、方法调用(PerformSelector)
			- [x] 2.GCD Async Main Queue
			- [x] 3.事件响应、手势识别、界面刷新
			- [x] 4.网络请求
			- [x] 5.自动释放池 AutoreleasePool
		3.节省CPU资源,提高程序性能
			- [x] 程序运行起来时,当什么操作都没有做的时候,RunLoop就告诉CUP,现在没有事情做,我要去休息,这时CUP就会将其资源释放出来去做其他的事情,当有事情做的时候RunLoop就会立马起来去做事情
	什么是RunLoop?
		- [x] 之所以,iOS App 能持续响应,保证程序运行状态,在于其有一个事件循环——Event Loop
		- [x] 事件循环机制,即线程能随时响应并处理事件的机制。这种机制要求线程不能退出,而且需要高效的完成事件调度与处理。
		- [x] 事件循环在很多编程语言,或者说不同的操作系统层面都支持。比如 JS中的事件循环、Windows下的消息循环,在 iOS/macOS 下,该机制就称为 RunLoop。
		举一个生活中的????
			- [x] 进程是一家工厂,线程是一个流水线,RunLoop就是流水线上的主管;当工厂接到商家的订单分配给这个流水线时,RunLoop就启动这个流水线,让流水线动起来,生产产品;当产品生产完毕时,RunLoop就会暂时停下流水线,节约资源。
			- [x] RunLoop管理流水线,流水线才不会因为无所事事被工厂销毁;而不需要流水线时,就会辞退RunLoop这个主管,即退出线程,把所有资源释放。

(十九) iOS Socket

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lCDqOAWK-1607667184387)(./Res/Socket.png)]

Socket
	mac查看端口占用情况及杀死进程
		- [x] https://www.jianshu.com/p/d03c1f4e5cf1
	UDP的连接步骤
		UDP编程的服务器端一般步骤是
			- [x] 1、创建一个socket,用函数socket();
			- [x] 2、设置socket属性,用函数setsockopt();* 可选
			- [x] 3、绑定IP地址、端口等信息到socket上,用函数bind();
			- [x] 4、循环接收数据,用函数recvfrom();
			- [x] 5、关闭网络连接;
		UDP编程的客户端一般步骤是
			- [x] 1、创建一个socket,用函数socket();
			- [x] 2、设置socket属性,用函数setsockopt();* 可选
			- [x] 3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选
			- [x] 4、设置对方的IP地址和端口等属性;
			- [x] 5、发送数据,用函数sendto();
			- [x] 6、关闭网络连接;
	- [ ] WebSocket
	Socket
		客户端和服务端建立长连接经过了以下的步骤
			服务器端的步骤是
				- [x] 1、创建一个socket,用函数socket();
				- [x] 2、设置socket属性,用函数setsockopt(); * 可选
				- [x] 3、绑定IP地址、端口等信息到socket上,用函数bind();
				- [x] 4、开启监听,用函数listen();
				- [x] 5、接收客户端上来的连接,用函数accept();
				- [x] 6、收发数据,用函数send()和recv(),或者read()和write();
				- [x] 7、关闭网络连接;
				- [x] 8、关闭监听;
			客户端的步骤为:
				- [x] 1、创建一个socket,用函数socket();
				- [x] 2、设置socket属性,用函数setsockopt();* 可选
				- [x] 3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选
				- [x] 4、设置要连接的对方的IP地址和端口等属性;
				- [x] 5、连接服务器,用函数connect();
				- [x] 6、收发数据,用函数send()和recv(),或者read()和write();
				- [x] 7、关闭网络连接;

(十八) iOS 逆向

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j1s9twUq-1607667184389)(./Res/Hook.png)]

逆向了解-有道云笔记
	Hook
		- [x] HOOK(钩子) 其实就是改变程序执行流程的一种技术的统称!
		iOS中HOOK技术的几种方式-有道云笔记
			1、Method Swizzle
				- [x] 利用OC的Runtime特性,动态改变SEL(方法编号)和IMP(方法实现)的对应关系,达到OC方法调用流程改变的目的。主要用于OC方法。
			2、fishhook
				- [x] 它是Facebook提供的一个动态修改链接mach-O文件的工具。利用MachO文件加载原理,通过修改懒加载和非懒加载两个表的指针达到C函数HOOK的目的。
			3、Cydia Substrate
				- [x] Cydia Substrate 原名为 Mobile Substrate ,它的主要作用是针对OC方法、C函数以及函数地址进行HOOK操作。当然它并不是仅仅针对iOS而设计的,安卓一样可以用。官方地址:http://www.cydiasubstrate.com/
	Aspects
		- [x] Aspects是一个轻量级的面向切面编程的库。它能允许你在每一个类和每一个实例中存在的方法里面加入任何代码。可以在以下切入点插入代码:before(在原始的方法前执行) / instead(替换原始的方法执行) / after(在原始的方法后执行,默认)。通过Runtime消息转发实现Hook。Aspects会自动的调用super方法,使用method swizzling起来会更加方便。

(十七) iOS 路由
Router路由
	阿里巴巴(BeeHive)/美团/蘑菇街等的路由是怎么做的?实践时候还是选用大厂方案比较靠谱
	路由器就是一个任务调度中心
	002-带你一步步构建iOS路由
		路由的安全-中间件中实现
			- [x] 风控业务
			- [x] 认证机制
			- [x] 加密验签
		路由的效率
			- [x] 同步阻塞型
			- [x] 升级为异步非阻塞型
		路由的使用
			- [x] 充当MVVM的ViewModel中比较解耦的目标获取逻辑
			- [x] VIPER中Router层,P与V的调用全部靠Router转发
	001-移动端路由层设计-有道云笔记-iOS路由
		- [x] 什么是移动端路由层
		- [x] 移动端路由层需要解决的问题
		- [x] 移动端路由所应用的场景
		- [x] 对外如何定义资源
		- [x] iOS与Android的系统访问机制、统一的链接协议
	- [x] 代码示例demo-万能路由跳转:1.NIiOS_GitHub/proj_2020/026YSC-Class-DetailList-Demo_\*\*\*/YSC-Class-DetailList-Demo/YSC-Class-DetailList-Demo/XXJumpControllerTool.h

(十六) iOS 网络请求强化
001-iOS 网络:HTTP 请求 见:思维导图(源码解读)/有道云笔记
    NSURLConnection
        - [x] 1.同步GET请求
        - [x] 2. 异步GET请求
        - [x] 3. 通过代理发送异步请求
        - [x] 4. 同步POST请求
        - [x] 5. 异步POST请求
        - [x] 6. NSURLConnection 中文URL处理
    NSURLSession
        - [x] 1.GET请求
        - [x] 2.POST请求
        - [x] 3.通过代理发送请求
    AFNetworking
        1.GET请求
            - [x] AFHTTPSessionManager内部包装了NSURLSession
        2.POST请求
            - [x] AFHTTPRequestOperationManager内部包装了NSURLConnection

(十五) iOS Block复习(之前资料已有复习记录-这里来强化复习下吧)
return_type 表示返回的对象/关键字等(可以是void,并省略)
blockName 表示block的名称
var_type 表示参数的类型(可以是void,并省略)
varName 表示参数名称

Block标准声明与定义
return_type(^blockName)(var_type) = ^return_type(var_type varName){
    // ...
};

返回值类型 (^变量名) (参数列表) = 返回值类型 (参数列表) {
    // 表达式 
};
001-iOS 开发:『Blocks』详尽总结 (一)基本使用 见:有道云笔记、总结思维导图
002-iOS 开发:『Blocks』详尽总结 (二)底层原理 见:有道云笔记、总结思维导图 

(十四) iOS Runtime复习
001-iOS 开发:『Runtime』详解(一)基础知识 见:有道云笔记、总结思维导图
应用案例:-proj_2020/006Runtime

002-iOS 开发:『Runtime』详解(二)Method Swizzling(动态方法交换) 见:有道云笔记、总结思维导图
应用案例:-NIiOS_GitHub/proj_2020/024YSC-Runtime-MethodSwizzling/Runtime-MethodSwizzling02

Runtime运行时系统中最具争议的黑魔法:Method Swizzling(动态方法交换) Method Swizzling四种方案:
	- [x] D:优秀的第三方框架:JRSwizzle 和 RSSwizzle
	- [x] C:在其他类中添加 Method Swizzling 交换方法
	- [x] B:在该类的分类中添加 Method Swizzling 交换方法,但是使用函数指针的方式。
	- [x] A:在该类的分类中添加 Method Swizzling 交换方法,用普通方式

Method Swizzling应用场景:(工具类待总结进入 NITools by:nixs 2020年11月23日)
	- [x] 5.APM(应用性能管理)、防止程序崩溃
	- [x] 4.TableView、CollectionView 异常加载占位图
	- [x] 3.处理按钮重复点击
	- [x] 2.字体根据屏幕尺寸适配
	- [x] 1.全局页面统计功能

003-iOS 开发:『Runtime』详解(三)Category 底层原理 见:有道云笔记、总结思维导图

004-iOS 开发:『Runtime』详解(四)获取类详细属性、方法

--- 在ios 13之后,UITextField禁止通过KVC修改属性,以下提供两种方式(参考:https://blog.csdn.net/Harvey_DHui/article/details/105167550)
    -   注:026YSC-Class-DetailList-Demo已经有实现,解决方案如下
    解决方式1:通过attributedPlaceholder属性修改Placeholder颜色
    解决方式2:为UITextField重新写一个方法

---***--- 万能控制器跳转-为路由跳转做准备
    -   注:026YSC-Class-DetailList-Demo已经有实现,解决方案如下
    * 需求:
    1.某个页面的不同 banner 图,点击可以跳转到不同页面。
    2.推送通知,点击跳转到指定页面。
    3.二维码扫描,根据不同内容,跳转不同页面。
    4.WebView 页面,根据 URL 点击不同,跳转不同的原生页面。
    ...
    * 分析:先来思考一下几种解决方法。
    方法 1:在每个需要跳转的地方写一堆判断语句以及跳转语句。
    方法 2:将判断语句和跳转语句抽取出来,写到基类,或者对应的 Category 中。
    方法 3:利用 Runtime,定制一个万能跳转控制器工具。
    * 实现步骤:
    1.事先和服务器端商量好,定义跳转不同控制器的规则,让服务器传回对应规则的相关参数。
        比如:跳转到 A 控制器,需要服务器传回 A 控制器的类名,控制器 A 需要传入的属性参数(id、type 等等)。
    2.根据服务器传回的类名,创建对应的控制器对象;
    3.遍历服务器传回的参数,利用 Runtime 遍历控制器对象的属性列表;
    4.如果控制器对象存在该属性,则利用 KVC 进行赋值;
    5.进行跳转。

--- 实现字典转模型(注:可以去看下MJExtension的源码对比学习下)
    1.在日常开发中,将网络请求中获取的 JSON 数据转为数据模型,是我们开发中必不可少的操作。通常我们会选用诸如 YYModel、JSONModel 或者 MJExtension 等第三方框架来实现这一过程。这些框架实现原理的核心就是 Runtime 和 KVC,以及 Getter / Setter。
    2.实现的大体思路如下:借助 Runtime 可以动态获取成员列表的特性,遍历模型中所有属性,然后以获取到的属性名为 key,在 JSON 字典中寻找对应的值 value;再使用 KVC 或直接调用 Getter / Setter 将每一个对应 value 赋值给模型,就完成了字典转模型的目的。
    3.字典中取值除了字符串之外,还有数组和字典。那么在将字典转换成数据模型的时候,就要考虑 模型嵌套模型、模型嵌套模型数组 的情况了
    4.// 对特殊属性进行处理
      // 判断当前类是否实现了协议方法,获取协议方法中规定的特殊属性的处理方式
      // 处理:字典的 key 与模型属性不匹配的问题,如 id -> uid

005-iOS 开发:『Runtime』详解(五)Crash 防护系统(Runtime消息转发:消息动态解析、消息接收者重定向、消息重定向)
    
    通过 Runtime 机制可以避免的常见 Crash :
        1.unrecognized selector sent to instance(找不到对象方法的实现)
        2.unrecognized selector sent to class(找不到类方法实现)
        3.KVO Crash
        4.KVC Crash
        5.NSNotification Crash
        6.NSTimer Crash
        7.Container Crash(集合类操作造成的崩溃,例如数组越界,插入 nil 等)
        8.NSString Crash (字符串类操作造成的崩溃)
        9.Bad Access Crash (野指针)
        10.Threading Crash (非主线程刷 UI)
        11.NSNull Crash

    iOS 开发:『Crash 防护系统』(一)Unrecognized Selector
        通过本文,您将了解到:
        Crash 防护系统开篇
        防护原理简介和常见 Crash
        Method Swizzling 方法的封装
        Unrecognized Selector 防护
        4.1 unrecognized selector sent to instance(找不到对象方法的实现)
        4.2 unrecognized selector sent to class(找不到类方法实现)

    iOS 开发:『Crash 防护系统』(二)KVO 防护(针对Crash防护的学习,一定要明白Bugly到底做了什么!!!,出现了异常是怎么上送到异常管理后台的?)
        KVO 日常使用造成崩溃的原因通常有以下几个:
        1.KVO 添加次数和移除次数不匹配:
            *移除了未注册的观察者,导致崩溃。
            *重复移除多次,移除次数多于添加次数,导致崩溃。
            *重复添加多次,虽然不会崩溃,但是发生改变时,也同时会被观察多次。
        2.被观察者提前被释放,被观察者在 dealloc 时仍然注册着 KVO,导致崩溃。
        例如:被观察者是局部变量的情况(iOS 10 及之前会崩溃)。
        3.添加了观察者,但未实现 observeValueForKeyPath:ofObject:change:context: 方法,导致崩溃。
        4.添加或者移除时 keypath == nil,导致崩溃。
    
    iOS 开发:『Crash 防护系统』(三)KVC 防护
        1.KVC Crash 的主要原因
        2.KVC 搜索模式
        3.KVC Crash 防护方案

        KVC 日常使用造成崩溃的原因通常有以下几个:
        1.key 不是对象的属性,造成崩溃。
        2.keyPath 不正确,造成崩溃。
        3.key 为 nil,造成崩溃。
        4.value 为 nil,为非对象设值,造成崩溃。
(十三) Android/iOS sqlite数据库处理 - WCDB、key-value处理 - MMKV
项目待实践:
https://github.com/Tencent
(十二) iOS基础概念、关键字 见:有道云笔记、总结思维导图
(十一) KVC-KVO 见:有道云笔记
KVC、KVO探识(一)KVO和KVO的详细使用
KVC、KVO探识(二)KVC你不知道的东西
KVC、KVO探识(三)KVC你不知道的细节(执行顺序)
KVC、KVO探识(四)KVO准备篇(类与对象)
KVC、KVO探识(五)KVO底层实现原理

应用案例:KVC私有属性赋值、KVC私有属性取值-proj_2020/KVC-KVO demo

复习:2020-iOS/OC基础(OC基础篇)/018-成员变量、实例变量、属性变量 、全局变量、局部变量详解 http://note.youdao.com/s/U173cSIh

应用案例:iOS中KVO的使用 见:有道云笔记 2020-iOS/iOSKVC-KVO/006-iOS-iOS中KVO的使用-KVO的概述与使用 -proj_2020/KVC-KVO/StockViewController.h/m demo

2020-iOS/iOSKVC-KVO/008---KVC和KVO的底层原理(推荐!!!) http://note.youdao.com/s/Hz9LP9LD

iOS下KVO使用过程中的陷阱 https://www.jianshu.com/p/59afe9997f04
(十一) iOS优秀组件博客 见:有道云笔记「CocoaPods+架构+组件/003-组件开发/004-iOS优秀组件博客」
(十) iOS签名验签 - 个人CSDN博客有记录
iOS 的 (签名验签)Code Signing 体系-https://blog.csdn.net/wvqusrtg/article/details/109611935    
(九) iOS文件上传、下载
/*
 //文件下载
 001 NSData *data = [NSData dataWithContentsOfURL:<#(nonnull NSURL *)#>]
 问题:
 "1)只能处理小文件,如果文件过大那么会造成内存飙升问题
 "2)不能监听下载进度
 "3)性能不好
 
 002 NSURLSession发请求下载文件(代理)
 1 监听文件的下载进度:
 下载进度 = 当前已经下载的数据大小/文件的总大小
 当前已经下载的数据大小 ===> 累加
 文件的总大小         ===> 响应头中得到
 
 2 内存飙升
 边接收数据边把数据写入到沙盒中 NSFileHandle
 ① 在磁盘中创建一个空的文件
 ② 创建文件句柄指针指向该文件
 ③ 当接收到数据之后使用文件句柄来写数据("边写数据边移动指针")
 ④ 关闭文件句柄
 
 3 什么是句柄指针
 广义而言,能够从一个数值拎起一大堆数据的东西都可以叫做句柄,英文名为 handle
 指针其实也是一种“句柄”,只是由于指针同时拥有更特殊的含义————实实在在对应内存里的一个地址
 指针也有着能从一个32位的值里引用到一大堆数据的作用
 
 4 断点续传下载
 ① 设置请求头(从请求头内拼接上次下载量的参数,可以做到从上次下载量开始下载)
 ② 将句柄指针指向当前下载文件的末尾,便于下次下载
 ③ 每次保存当前下载文件量
 */

4.iOS 【NSURLSession 下载文件(解决内存飙升/句柄指针/离线断点续传)】
    https://wangzhongyao.blog.csdn.net/article/details/50564322?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2.channel_param
3.iOS 网络:『文件下载、断点下载』的实现(三):AFNetworking - 「注意看评论(雨天多久就):对AFNetWorking的下载理解!!!」
    https://www.jianshu.com/p/01390c7a4957
2.iOS 网络:『文件下载、断点下载』的实现(二):NSURLSession -「断点下载数据最好还是存储到本地DB库里-可以考虑ORM三方操作DB库」
    https://www.jianshu.com/p/5a07352e9473
1.iOS 网络:『文件下载、断点下载』的实现(一):NSURLConnection
    https://www.jianshu.com/p/ce3eaee74bde

*** NSURLConnection下载大文件 - 引入MBProgressHUD - by:nixs 这里hud没有从父视图中清理掉,待探究;-注意其中用到了Runloop
(八) iOS多线程
5.005-iOS 深入理解RunLoop - https://blog.ibireme.com/2015/05/18/runloop/
4.004-iOS 多线程:『RunLoop』详尽总结(实例:NIiOS_GitHub/proj_2020/019YSC-RunLoopDemo)
http://note.youdao.com/s/8s7apxxx

    (ImageView推迟显示:当界面中含有UITableView,而且每个UITableViewCell里面都有图片.这时候当我们滚动UITableView时候,如果有一堆的图片需要显示,那么可能会出现卡顿的现象。怎么解决这个问题呢?这个时候,我们应该推迟图片的显示,也就是ImageView推迟显示图片)

    (后台常驻线程:我们在开发应用程序的过程中,如果后台操作特别频繁,经常会在子线程做一些耗时操作(下载文件、后台播放音乐等),我们最好能让这条线程永远常驻内存。
    那么怎么做呢?添加一条用于常驻内存的强引用的子线程,在该线程的RunLoop下添加一个Sources,开启RunLoop。)-注意:结合大文件的后台上传/下载
    
3.003-iOS 多线程:『NSOperation、NSOperationQueue』详尽总结(实例:NIiOS_GitHub/proj_2020/018YSC-NSOperation-demo)
http://note.youdao.com/s/ZlYBVpkM
2.002-iOS 多线程:『pthread、NSThread』详尽总结(实例:NIiOS_GitHub/proj_2020/017YSC-pthread-NSThread-demo)
http://note.youdao.com/s/ILbenzJ1
1.001-iOS 多线程:『GCD』详尽总结(实例:NIiOS_GitHub/proj_2020/016YSC-GCD-demo)
http://note.youdao.com/s/KIMmr9jV
(七) iOS适配/布局
1.Masonry自动布局对UIScrollView的内容自适应(亦可以参考我的CSDN博客)
http://note.youdao.com/s/ZDLsB5OP
(六) docker-gitlab-Cocoapods私有组件需求(20200818)
  • iMac docker里导出指定容器tag-制作镜像 ->MacBookPro导入上面导出镜像->添加容器选择上一步导入的镜像

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pugfTVRB-1607667184391)(./Res/20200817Cocoapod公私有库/iMacDocker.png)]

  • 本项目为iMac办公机上安装docker,docker里安装gitlab启动 git版本控制;-by:nixs 2020年08月18日15:07:09

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2RiYDC9K-1607667184393)(./Res/20200817Cocoapod公私有库/Cocoapods.png)]

(五) iOS组件化基础(20200817)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I9jrfFS5-1607667184399)(./Res/20200817Cocoapod公私有库/20200817-iOS组件化.png)]

(四) OC基础(OC基础篇)

9.runtime应用实例
http://note.youdao.com/s/22YpZHm3

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1jY9gxXs-1607667184399)(./Res/006-runtime.png)]

8.在Block中一起使用weakSelf与strongSelf的含义
http://note.youdao.com/s/cnmk6gYI

7.Block约定:用法中的符号含义列举如下:
http://note.youdao.com/s/EZCNfKT0


return_type 表示返回的对象/关键字等(可以是void,并省略)
blockName 表示block的名称
var_type 表示参数的类型(可以是void,并省略)
varName 表示参数名称

Block标准声明与定义
return_type(^blockName)(var_type) = ^return_type(var_type varName){
    // ...
};

6.iOS基础·属性的修饰词与setter的关系(@property、@synthesize、@dynamic、retain、assign、copy、weak、strong、nonatomic、atomic、readonly、readwrite等修饰词与setter、getter等存取方法之间的关系)
http://note.youdao.com/s/LlO3kbE

5.iOS基础:全局变量·静态变量·局部变量·自动变量(static、extern、全局静态区、堆区、栈区)
http://note.youdao.com/s/Y6fzB5Ud

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BOElY2ef-1607667184400)(./Res/004-变量.png)]

4.了解-编程语言傻傻分不清:弱类型、强类型、动态类型、静态类型
http://note.youdao.com/s/OKC27LrL

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w5ZNcMY4-1607667184401)(./Res/003-编程语言.png)]

3.1 UIView+Frame.h/m分类

3.分类(Category)扩展(Extension)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VgS9uVv6-1607667184402)(./Res/002-Category-Extension.png)]

如下-有时间就看下...
[2.runtime从入门到精通(二)—— 官方文档翻译](https://blog.csdn.net/coyote1994/article/details/52441513)

[1.runtime从入门到精通(一)—— 初识runtime](https://blog.csdn.net/wvqusrtg/article/details/107179786)

[0.新手也看得懂的 iOS Runtime 教程](http://www.lymanli.com/2018/03/15/%E6%96%B0%E6%89%8B%E4%B9%9F%E7%9C%8B%E5%BE%97%E6%87%82%E7%9A%84-iOS-Runtime-%E6%95%99%E7%A8%8B/)

(二) 后续待整理
0.把LeanCloud云储存搞一遍,后续最起码不用部署服务器就能写云储存的App了,如果量级(性能要求)上去了-考虑重新写后端(首选Java-因为Java我这边还能写「微服务、阿里云ECS/RDS/OSS/CDN+SLB」);
1.拍小视频类似微信视频编辑-ThinkSNS借鉴;
2.腾讯直播方案可以了解下;
3.YYkit 源码Demo撸一遍;

(三) 「NIiOS」Demo开发库整理进行时
Flowing:2019年05月28日
69.iOS高德获取经纬度(单次获取)
Flowing:2019年03月21日
68.UITableView+FDTemplateLayoutCell.h 进阶「UITableView+FDTemplateLayoutCell(二)」
67.优化UITableViewCell高度计算的那些事 http://blog.sunnyxx.com/2015/05/17/cell-height-calculation/

Flowing:2019年03月20日
66.layoutSubviews layoutIfNeeded setNeedsLayout 的区别:https://blog.csdn.net/sunshine__hui/article/details/51499981
66.iOS横竖屏旋转及其基本适配方法 https://blog.csdn.net/DreamcoffeeZS/article/details/79037207
65.iOS横屏开发 https://www.jianshu.com/p/3d1babc5bcc4
64.iOS开发 - 短信验证码倒计时按钮;
63.iOS获取图片的大小(宽高)「本地图片&远程网络图片」;

Flowing:2019年03月19日
62.iOS获取图片的大小(宽高)地址:https://www.jianshu.com/p/5412c1862c8a?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
61.一行代码实现Badge效果(iOS) BADGE IN ONE LINE(iOS)
60.第三方登陆、分享集成-推荐OpenShare;
59.微信支付开通条件了解下;

Flowing:2019年03月18日
59.LeanCloud数据存储、读取进一步学习;

Flowing:2019年03月16日
58.Swift纯代码项目练手-Snapkit布局「和OC的Masnory同级」基础使用

Flowing:2019年03月15日
57.Swift 最新语法过一遍,比如最新开发中用到的一个折线图上气泡绘制,OC调Swift;推荐Swift学习地址[Swift变成语言](https://www.cnswift.org/a-swift-tour)

Flowing:2019年03月14日
56.关于iOS端推送、推送拓展(NotificationService)、基础推送、VOIP推送及各个证书制作流程、上线流程等相关内容有需要-小伙伴谁想了解私聊小编;
55.YTKNetWorking使用可以参考“推推管家”这个不怎么滴的应用里有用-小伙伴谁想了解私聊小编;
54.LeanCloud在线商品发布朋友圈简单商品发布Demo;

Flowing:2019年03月13日
53.LeanCloud在线商品发布朋友圈简单布局;

Flowing:2019年03月12日
52.UICollectionView简单瀑布流;
51.LeanClouod结合UICollectionView 对象 和 图片文件存储「后续自己搞着玩的应用没有接口的前提下可以先用LeanCloud存储数据」(数据响应的性能考虑,数据异步请求完成回到主线程刷新UI);
50.不想写后台接口了-LeanCloud引入学习(基础的数据调用还是够的,后续数据量级够了再引入后台接口)(https://leancloud.cn/docs/start.html)

Flowing:2019年03月11日
49.调用系统邮件发送功能 || 或提示框给出要接收邮件人邮箱地址;(/Users/nixs/Documents/NIiOS/NIiOS/Module/Main/C/LeftViewController.m)

Flowing:2019年02月28日
48.RunTime应用实例;

Flowing:2019年02月20日
47.UICollectionView step2:在自定义View上嵌套UICollectionView-item选定 & 全部反选 & 确定提交 & 页面传值封装;

Flowing:2019年02月19日
46.UICollectionView step2:在自定义View上嵌套UICollectionView;


Flowing:2019年02月14日
45.UICollectionView基础&拖动特性 勿忘扩展删除+新增Item;
44.多线程下载基础NSData/NSURLConnection方式(小文件、大文件&进度条展示);

Flowing:2019年02月12日
43.***iOS多线程(thread/NSThread/GCD/NSOperation/NSOperationQueue);

Flowing:2019年01月31日
42.加解密基础;
41.KVC键值编码、KVO键值监听;
40.表格cell高度计算5中方案(AutoLayout/CountHeight/Frame/YYKit/ASDK);
39.二维码图片合成;


Flowing:2018年12月X日
38.iOS多线程整理;

Flowing:2018年12月14日
39.tableViewCell xib布局 和 纯代码布局区别;
38.(AES128+Base64) URLEncode编码

Flowing:2018年12月12日
37.iOS手势解;
    "0.设置手势密码",
    "1.登陆手势密码",
    "2.验证手势密码",
    "3.修改手势密码"

Flowing:2018年12月10日
36.新增全局宏定义 支持iphoneX/iphoneXR/iphoneXS/iphoneXS_Max;

#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)

#define kSCREEN_MAX_LENGTH (MAX(kScreenWidth, kScreenHeight))
#define kSCREEN_MIN_LENGTH (MIN(kScreenWidth, kScreenHeight))

#define IS_IPHONE4 (IS_IPHONE && kSCREEN_MAX_LENGTH < 568.0)
#define IS_IPHONE5 (IS_IPHONE && kSCREEN_MAX_LENGTH == 568.0)
#define IS_IPHONE6 (IS_IPHONE && kSCREEN_MAX_LENGTH == 667.0)
#define IS_IPHONE6P (IS_IPHONE && kSCREEN_MAX_LENGTH == 736.0)
#define IS_IPhoneX (kScreenWidth == 375.0f) && (kScreenHeight == 812.0f) && IS_IPHONE
//iPhoneX / iPhoneXS
#define  isIphoneX_XS     (kScreenWidth == 375.f && kScreenHeight == 812.f ? YES : NO)
//iPhoneXR / iPhoneXSMax
#define  isIphoneXR_XSMax    (kScreenWidth == 414.f && kScreenHeight == 896.f ? YES : NO)
//异性全面屏
#define   isFullScreen    (isIphoneX_XS || isIphoneXR_XSMax)

// 状态栏高度
#define  kStatusBarHeight      (isFullScreen ? 44.f : 20.f)
// 导航栏高度
#define  kNavigationBarHeight  44.f
// TabBar高度
#define  kTabbarHeight        (isFullScreen ? (49.f+34.f) : 49.f)
// Tabbar底部安全区
#define  kTabbarSafeBottomMargin        (isFullScreen ? 34.f : 0.f)
// 导航栏+状态栏高度
#define  kStatusBarAndNavigationBarHeight  (isFullScreen ? 88.f : 64.f)


35.*** - iOS操作基本Plist文件-待进一步更新理解学习;
34.iMac上代码段更新 和 MacBookPro保持同步;-CodeSnippets 代码段库 在git上

Flowing:2018年12月08日
33.SourceTree iMac上管理代码仓库;
32.证书切换为用鹏哥的个人证书;
31.代码仓库迁移到git 码云里-变成私有仓库;

Flowing:2018年12月07日
30.图片验证码绘制;

29.单例宏定义-快速单例实例化 注:不要忘记遵循两个代理NSCopying ,NSMulCopying;
28.单例的进一步理解使用 & 实例;

Flowing:2018年12月03日
27.加载在线和本地Web页面-cocoapods引入第三方(#2018年12月03日10:52:19-https://github.com/xiubojin/JXBWKWebView
    pod 'JXBWebKit', '~> 1.0.6')
{   //新增了 X 关闭按钮的资源文件(图片资源)
    //修改了源码里文件 JXBWebViewController.m line:265
    //JXBWebViewController *niWebVC = [[JXBWebViewController alloc] initWithURLString:model1.url];

    注:JXBWebViewController.h/m是可以获取XXX.html里的title的
}

Flowing:2018年11月29日
26.IOS异步获取数据并刷新界面dispatch_async的使用方法 参考链接:https://www.cnblogs.com/wangxiaorui/p/5390088.html

Flowing:2018年11月27日
25.更新头部导航颜色值和头部有轮播图控制器对比比较鲜明;
24.首页-预演 分组展示Demo栏目;

Flowing:2018年11月26日
23.iOS基类表格初始化-能传入表格类型自定义封装;
22.iOS表格布局 表头、表尾、区头、区尾整理封装;

Flowing:2018年11月23日
21.二维码保存相册-屏蔽;
20.二维码保存相册-整理完成;

Flowing:2018年11月22日
19.保存指定区域View作为图片 到系统相册;
18.优化去除头部导航栏下方黑线
    //设置导航栏背景颜色
    UIImage *img = [UIImage getImageWithColor:[UIColor redColor]];
    [self.navigationController.navigationBar setBackgroundImage:img  forBarMetrics:UIBarMetricsDefault];
    self.navigationController.navigationBar.shadowImage = [[UIImage alloc] init];

17.我的/名片自定义View分类引入
16.新增据颜色值生成图片分类

Flowing:2018年11月20日
15.HomeViewController.h/m 表格-轮播图-换成表格的第一个cell里显示
    HomeViewController.h/m 表格头视图-轮播图(本方案也行-是原来写的有BUG-确定实行还是本方案)

Flowing:2018年11月19日
14.HomeViewController.h/m 表格头视图-轮播图
13.加载网页封装里新增获取网页标题 
12.加载网页封装VC;
11.抽屉引入 pod 'CWLateralSlide'使用自定义转场动画实现的0耦合、0侵入、0污染的抽屉框架;
10.启动广告引入:AdvertiseHelper.h/m
9.Pch/NIConstant.h/m常量值抽取-便于做国际化
8.版本检查自定义View引入 NIVersionManagerView.h/m
7. Toast使用 https://github.com/scalessec/Toast
6.网络检测通知引入 + 网络检测自定义View引入 NINetWorkDetectionView.h/m

Flowing:2018年11月19日
5.Base基类补充(自定义nav/tab/BaseViewController/BaseModel)
4.[iOS 找出导航栏下面的黑线(可隐藏,改变样式等)](https://www.jianshu.com/p/effa4a48f1e3)
3.Utils/Catagory/UIView+NIExtension.h 分类整理
2.#import pod 依赖找不到 Build Settings/User Header Search Paths /新增:$(SRCROOT) - recursive
1.PCH引入 Build Settings/Prefix Header/$(SRCROOT)/NIiOS/Pch/GlobalPrefixHeader.pch
0.Xcode后续打包编码问题 #Xcode里配置:项目名->Target->Build Settings->Enable BitCode中设置为NO就可以了.

上一篇:【Flink】Flink netty 通讯 PartitionRequestClient NettyPartitionRequestClient


下一篇:中高级iOS必备知识点之 RunLoop(一)