知识点归档,博客记录

由于本人能力有限,难免有错,欢迎批评、指正、补充,目录请看右下角

Foundation复习

UIKit复习

其他知识点回顾

RunLoop、RunTime、多线程、锁
各种锁
Data race的定义很简单:当至少有两个线程同时访问同一个变量,而且至少其中有一个是写操作时,就发生了Data race。
原子操作: 表示一条不可打断的操作,也就是说线程在执行操作过程中,不会被操作系统挂起,而是一定会执行完。
临界区:指的是一块对公共资源进行访问的代码,并非一种机制或是算法

你调用 sychronized 的每个对象,Objective-C runtime 都会为其分配一个递归锁并存储在哈希表中
复制代码

网络相关

计算机网络
组件化
架构思想 设计模式
生命周期
适配相关
动画相关 QuartzCore&CoreGraphics

----QuartzCore-----

--UIDynamic---

事件传递相关
本地+远程推送
Swift与OC、C++与OC混合开发、js交互、 Hyrb相关、MRC与ARC混编
WebKit.framework
NSHTTPCookieStorage
JavaScriptCore.framework
Foundation与CoreFoundation桥接
预编译指令
#define 没有参加编译,在预处理的时候就被替换掉了。
typedef参加编译和链接。
typedef是重命名,可以为枚举结构体等等重新命名,提高代码整洁。
复制代码
正则 Regular Expression
NSPredicate
NSRegularExpression
持久化相关
property list
沙盒
沙盒是三个Container可不只是Document、Library\Cache|Preferences、Temp这三个
---MyApp---
-- 1. BundleContainer(MyApp.app)
-- 2.DataContainer(Document、Library\Cache|Preferences、Temp、SystemData这个新发现的)
--3. iCloudContainer
复制代码

-[在组件化开发中要注意bundle的获取]

SQLite/FMDB
FMDatabaseQueue 解决这个问题的思路是:创建一个队列(串行线程队列),然后将放入的队列的block顺序执行,这样避免了多线程同时访问数据库
复制代码
keyChain
CoreData
  • [暂时不整了]
NSUserDefaults
App Groups
优化工具
Instruments
Allocations对app优化非常有用,通常是拿来分析内存增加(不一定是内存泄漏)和app中各部分占用内存问题,当我们得知哪个内存占用比较多,我们直接进行优化即可减少内存占用问题

Generation Analysis
这个功能是非常有用的,一般是这样用的:进入一个页面前mark一下,在退出这个页面的时候再mark一下可以比较哪些内容增加了,就可以具体分析哪些内存没有被释放;比如我们要进入日程界面的时候我点了一下mark
复制代码
静态分析Analyze、 监控僵尸对象、 memory graph 、 Debug View Hierachy
Crash搜集相关
Mach异常 、Unix Signal 和 NSException
1. Mach异常是最底层的内核级异常,如EXC_BAD_ACCESS(内存访问异常)

2. Unix Signal是Unix系统中的一种异步通知机制,Mach异常在host层被ux_exception
转换为相应的Unix Signal,并通过threadsignal将信号投递到出错的线程。如SIGABRT(
程序中止命令中止信号)、SIGALRM(程序超时信号),具体信号枚举在iOS的sys/signal.
h文件中。 它们可以利用Unix标准的signal机制来处理。

3. 当错误发生时候,先在最底层产生Mach异常;Mach异常在host层被转换为相应的Unix
Signal; 在OC层如果有对应的NSException(OC异常),就转换成OC异常,OC异常可以在
OC层得到处理;如果OC异常一直得不到处理,程序会强行发送SIGABRT信号中断程序。在
OC层如果没有对应的NSException,就只能让Unix标准的signal机制来处理了。

复制代码
僵尸对象:已经被释放掉的对象。一般来说,访问已经释放的对象或向它发消息会引起
错误。因为指针指向的内存块认为你无权访问或它无法执行该消息,这时候内核会抛出
一个异常( EXC ),表明你不能访问该存储区域(BADACCESS)。(EXC_BAD_ACCESS类型错误)

野指针是指向一个已删除的对象或未申请访问受限内存区域的指针。而这里的野指针主
要是对象释放后,指针未置空导致的野指针。该类Crash发生比较随机,找出来比较费劲
,比较常见的做法是,在开发阶段,提高这类Crash的复现率,尽可能得将其发现并解决。

向OC对象发出release消息,只是标记对象占用的那块内存可以被释放,系统并没有立即
收回内存;如果此时还向该对象发送其他消息,可能会发生Crash,也可能没有问题。下
图是 访问野指针(指向已删除对象的指针)可能发生的情况。

复制代码

  • [第三方平台搜集crash信息 PLCrashReporter、友盟、Bugly]
  • [MLeaksFinder]
  • [Crash 堆栈]
加密
base64
对称加密
  • [DES]
  • [AES]
非对称加密
哈希算法HASH(散列算法)
Hash函数的安全设计的理论主要有以下两点:一是函数的单向性,二是函数影射的随机性
hash算法是将输入内容变换为长度固定的输出,它主要是用于可以更快速地判断两个内容是否相同。
信息摘要是hash算法的一种,但拥有额外更严格的条件,例如不能逆运算,更严格的碰撞要求等。
复制代码
Jenkins+Docker、fastlane、fir.im/蒲公英 自动打包、单元测试、自动化测试、Xcode编译
持续化集成工具——Jenkins
iOS自动化打包命令——xcodebuild + xcrun 和 fastlane - gym 命令
打包完成自动化上传 fir / 蒲公英 第三方平台

CI 提供的是持续集成服务(Continuous Integration,简称 CI)。它绑定 Github 上面的项目,只要有新的代码,就会自动抓取。然后,提供一个运行环境,执行测试,完成构建,还能部署到服务器。

持续集成指的是只要代码有变更,就自动运行构建和测试,反馈运行结果。确保符合预期以后,再将新代码"集成"到主干。

持续集成的好处在于,每次代码的小幅变更,就能看到运行结果,从而不断累积小的变更,而不是在开发周期结束时,一下子合并一大块代码。
复制代码

---说真的我有点蒙蔽,没有真正实践过,只能以后参加新工作有机会弄了----

---单元测试----

app Thinning、封装动态库.dylib、封装静态库.a、封装带第三方的.a &.framework的sdk、封装.bundle

---App Thinning相关---

---封装动态库.dylib---

静态库: 一堆目标文件(.o/.obj)的打包体(并非二进制文件)
动态库: 一个没有main函数的可执行文件

静态库 常见的是 .a
动态库常见的是 .dll(windows),.dylib .tbd (mac),so(linux)
framework(in Apple): Framework 是Cocoa/Cocoa Touch程序中使用的一种资源打包方式,可以将代码文件、头文件、资源文件、说明文档等集中在一起,方便开发者使用
。也就是说我们的 framework其实是资源打包的方式,和静态库动态库的本质是没有关系的
Framework 可以选择创建为动态或者静态

静态库即静态链接库(Windows 下的 .lib,Linux 和 Mac 下的 .a)。之所以叫做静态,是因为静态库在编译的时候会被直接拷贝一份,复制到目标程序里,这段代码在目标程序里就不会再改变了。
静态库的好处很明显,编译完成之后,库文件实际上就没有作用了。目标程序没有外部依赖,直接就可以运行。当然其缺点也很明显,就是会使用目标程序的体积增大。

动态库动态库即动态链接库(Windows 下的 .dll,Linux 下的 .so,Mac 下的 .dylib)。与静态库相反,动态库在编译时并不会被拷贝到目标程序中,目标程序中只会存储指向动态库的引用。等到程序运行时,动态库才会被真正加载进来。
动态库的优点是,不需要拷贝到目标程序中,不会影响目标程序的体积,而且同一份库可以被多个程序使用(因为这个原因,动态库也被称作共享库)。同时,编译时才载入的特性,也可以让我们随时对库进行替换,而不需要重新编译代码。
动态库带来的问题主要是,动态载入会带来一部分性能损失,使用动态库也会使得程序依赖于外部环境。如果环境缺少动态库或者库的版本不正确,就会导致程序无法运行(Linux 下喜闻乐见的 lib not found 错误)。

这里的所谓静态和动态是相对编译期和运行期的:静态库在程序编译时会被链接到目标代码中,程序运行时将不再需要改静态库;而动态库在程序编译时并不会被链接到目标代码中,只是在程序运行时才被载入,因为在程序运行期间还需要动态库的存在。

复制代码
_CodeSignature: 保存签名相关文件
Headers: framework暴露的所有头文件
Info.plist: 描述了该framework所包含的项目配置信息
STDemo: 编译后的核心库文件
Modules: 模块相关文件夹, 目测只包含了module.modulemap文件
复制代码
被苹果签名的动态库可以(会)iOS应用加载
一个简单的iOS应用在启动时会加载超过150个动态库
Xcode不支持创建iOS上的动态库,frameworks或者插件,但解决这些还是非常容易的事情
如果没有代码签名,我们将可以像在MacOS上在iOS上加载动态库,frameworks和在运行时加载插件
在实践中内核将会杀掉哪些尝试加载一个未签名或者签名不能被审核的动态库
***一个要上架的动态库同样需要被同一个用来上架AppStore应用的证书签名***
最后AppStore的政策绝不运行动态库,即使技术是做到了,它也通不过AppStore的审核。

复制代码

---封装静态库.a----

----制作附带第三方.a或framework封装自己的SDK----

** 如果将第三方SDK的framework包含在自己的静态库中,
一种方法就是打包的时候不打包进自己的静态库中,然后在调用静态库的时候再在程序中引入第三方的SDK即可**
iOS静态库SDK制作也有提到具体如何操作,.framewrok的库确实无法整体直接打包进静态库中。没有办法直接整体打包,那么法间接的引入

复制代码
在自己的framework中使用到了AFN,fmdb 等第三方库。如果我在add进自己framework的时候 不勾选 target,那么在使用我的framework的时候,项目里面就必须有这些三方库,不然就回报错。
如果我勾选了 target,那么我的项目中就不能有这些第三方库,不然也会报错 提示 duplicate symbol。
综上, 能不能让自己framework中的第三方库代码 和 项目中的第三方库代码完全独立呢?我问了一些朋友 说的是 修改自己sdk中的第三方库类名,还有相关的宏等。这样做工作了好大,还有更简单的方式吗?

木有更简单的方式了,一般来说 相对统一才是正道吧,我觉得放在项目里最合适,framwork的体积也可以减小,还可以保证项目中代码没问题,
就是如果更新第三方以后,你的framwork代码需要做更改,但是你不觉得 这个工作量更小点么
复制代码

----封装.bundle---

---其他相关---

Architectures (架构)
指明选定的Target要求被编译生成的二进制包所支持的指令集,
而支持的指令集越多,就会编译出包含多个指令集代码的数据包,对应生成二进制包就越大,也就是ipa包会变大。
复制代码
调试技巧、编码规则、数据采集与埋点、发布流程

---调试技巧----

lldb 是llvm的调试器
复制代码
hook的方法大致可以分为3类:系统类的方法、系统类的Delegate方法、自定义类的方法。

viewPath 及 viewId 的生成及优化
1. SDK 在生成 viewPath 时,只到 view 所在的 UIViewController 级别,而非根部的 UIWindow。这样做也在一定程度上减少了viewPath 的长度。
2. viewPath只表示到距离 view 最近的一个 VC
3. UITableViewCell/UICollectionCell 的深度表示:虽然每个 Cell 都可能被复用,但是不同的 Cell 都对应一个唯一的indexPath,因此完全可以使用indexPath值来表示其深度
4. SDK 为了在新增/移除某一 view 时,尽量减少对已有 view 的深度的影响,调整了对节点的深度的计算方式:采用当前 view 位于其父 view 中的所有 同类型 子 view 中的index 值。
它的可读性很差。因此在此基础上又增加了每个节点的名称,节点的名称由当前节点的 view 的类名来表示。
5. 在包含子VC时,优化VC的深度的计算
  5.1 由于子VC的展现顺序可能不同,这种情况导致 viewPath 不可靠且无法保证唯一性
  5.2 VC 的深度的计算:不再采用其 view 的深度,而是直接使用固定的0。因为 VC 已经是viewPath的根级别了,它的深度信息已经不重要了。
  5.3 如果上述子 VC 的 VC1 和 VC2 是同一个类的不同实例,那么他们内部的视图结构是完全一样的,这时候如果使用固定的 VC 深度(0),通过viewPath就无法区分具体是哪个子 VC 的 view 了。
  针对这种同一类的不同实例,如果想进一步区分它们,SDK 采用了另一个方案:****页面别名****。????

viewPath:HYGHallSlideViewController-UIScrollView-HYGHallProductTableView-UITableViewWrapperView-HYGHallProductCell-UITableViewCellContentView-HYGHallProductView & 0-0-1-0-0:2-0-1
路径中各个节点的深度是:0-0-1-0-0:2-0-1

HYGHallSlideViewController[0]/UIScrollView[0]/HYGHallProductTableView[1]/UITableViewWrapperView[0]/HYGHallProductCell[0:2]/UITableViewCellContentView[0]/HYGHallProductView[1]

0:2表示cell的第0组第二行。indexpath的写法

**圈选:您需要根据业务需求,将需要分析的关键元素告诉我们。这个过程,就是圈选**

6. viewId:为了便于后台使用它作为 view 的唯一标识。因此 SDK 使用viewPath信息通过MD5加密生成一个固定长度的值作为viewId
7. iewPath 与 viewId 重复时的解决方案
   7.1 有时同一个viewPath的 view 具有不同的表现形式与作用,同一个viewPath对应多个事件,此时如果只使用viewPath无法区分出不同的状态或事件。
   7.2 DK 的解决方案是:viewPath + “其它信息” 。这里的 “其它信息” 是视不同情况而定的,比如: 在上面的情况1中,“其它信息” 就是按钮的 title
   SDK 在进行数据收集时,会上传 view 的这些信息,再结合圈选SDK就能让后台在做统计时区分出这些不同的事件了。
   
 8. 基于 viewPath 与 KVC 实现 SDK 的无埋点业务数据收集功能的实现
实现 SDK 的无埋点数据收集时,主要分为3步:上传KVC配置、请求KVC配置、业务数据的收集与上报。
   8.1 KVC配置 就是一些用来描述 App 应该在什么时机去收集什么数据的信息,包含的主要信息有:
appKey:用来标识是哪个应用
appVersion:用来标识应用的版本号
viewEvent:标识某个事件类型(收集时机),例如:ButtonClick、ListItemClick、ViewTap等
viewPath:目标 view 在viewTree中的信息
keyPath:目标 view 与要收集的业务数据间的关联路径,用于KVC取值
keyName:为要收集的业务数据定义一个key,最终组成 key-value 的形式上报。用于区分多个收集的数据
    8.2.1 上传KVC配置
利用 圈选SDK 上传 KVC配置 的操作对于用户是透明的,主要由开发人员进行上传与管理。
此操作可以在任何时候进行,在想要收集某个或某些版本的 App 中的业务数据时,上传相应的KVC配置信息至后台即可,达到了根据需要动态可配的效果。
    8.2.2 请求KVC配置
SDK 在初始化时会触发 KVC配置 的请求操作,从后台拉取 App 当前版本对应的所有KVC配置,并将请求结果缓存起来,以提供给下一步使用。
    8.3 业务数据的收集与上报
这个环节的核心是基于viewPath的 view 匹配,
主要实现是通过循环遍历viewPath的每个节点的信息与当前 view 及其父view 依次进行匹配。
因此这一步会产生一定的时间与性能消耗。为了尽可能减少这部分的操作,SDK 中使用了一些方式进行优化,其中一个就是基于缓存view的优化。

   8.4 具体匹配原则和优化看上面文章
复制代码
第一类是代码埋点,即在需要埋点的节点调用接口直接上传埋点数据,友盟、百度统计等第三方数据统计服务商大都采用这种方案;

第二类是可视化埋点,即通过可视化工具配置采集节点,在前端自动解析配置并上报埋点数据,从而实现所谓的“无痕埋点”, 代表方案是已经开源的Mixpanel;

第三类是“无埋点”,它并不是真正的不需要埋点,而是前端自动采集全部事件并上报埋点数据,在后端数据计算时过滤出有用数据,代表方案是国内的GrowingIO。
复制代码
  • [友盟埋点]
  • [减少埋点入侵 aop]
  • [避免每次点击都触发埋点,可以缓存一些在触发埋点请求]

----上架流程----

内存相关
常见控件使用和优化
1. UIScrollView

2. UITableView :UIScrollView、UITableViewCell、UITableViewController、UITableViewHeaderFooterView
//根据 indexPath 以动画的形式取消选中。调用此方法不会造成委托接受tableView:willDeselectRowAtIndexPath和tableView:didDeselectRowAtIndexPath:
//消息;不给UITableViewSelectionDidChangeNotification通知观察者;调用此方法不会产生任何滚动到取消行。
UIKIT_EXTERN NSNotificationName const UITableViewSelectionDidChangeNotification;

// 设置是否显示cell自带的自动排序控件
@property (nonatomic) BOOL   showsReorderControl; 
//UITableViewCell重排
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath;

复制代码
  • [UITableViewRowAction 删除按钮等的定制]
  • [多行cell同时编辑]
  • [UITableViewIndexSearch 表格的牵引数组中的放大镜]
  • [cell 重新排列、跨section排列]
  • [UITableViewFocusUpdateContext 焦点更新的上下文]
  • [iOS 11 UITableView变化]
  • 不等高cell 缓存?
  • [局部刷新、高度估算]
  • [Copy/Paste 三个代理方法]
//复制的时候三个方法必须被实现
- (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(5_0);
- (BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender NS_AVAILABLE_IOS(5_0);
- (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender NS_AVAILABLE_IOS(5_0);
复制代码

---UITableView一些优化点----

self.tableView.estimatedRowHeight = xxx;
self.tableView.rowHeight = UITableViewAutomaticDimension;
复制代码
GPU会通过图层一和图层二的颜色进行图层混合,计算出混合部分的颜色,最理想情况的计算公式如下:
R = S + D * ( 1 – Sa )
当UIView的opaque属性被设为YES以后,按照上面的公式,也就是Sa的值为1,这个时候公式就变成了:
R = S
即不管D为什么,结果都一样。
因此GPU将不会做任何的计算合成,不需要考虑它下方的任何东西(因为都被它遮挡住了),而是简单从这个层拷贝。
这节省了GPU相当大的工作量。由此看来,opaque属性的真实用处是给绘图系统提供一个性能优化开关!
复制代码

3. UICollectionView:UIScrollView、UICollectionViewCell、UICollectionViewController、UICollectionViewFlowLayout、UICollectionViewLayout、UICollectionViewTransitionLayout
1.1 在创建UITableView的时候,使用的是- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style用于判断是普通还是分组,
1.2 UICollectionViewLayout实际的作用是一样的,是用来设置cell的布局的,初始化collectionView的时候,一定要给他设置这个属性,否者不会显示。
UICollectionViewFlowLayout是UICollectionViewLayout的子类,给collectionView赋值的时候,一定要使用** UICollectionViewFlowLayout**初始化。
1.3 UICollectionViewFlowLayout和UICollectionViewLayout的关系就像是UIGestureRecognizer和UITapGestureRecognizer的一样。
一个是父类,一个是子类。使用的时候都用子类

复用的时候,首先头尾view要继承于
UICollectionReusableView,然后注册(分为nib和class两种)
UICollectionViewCell也是继承自UICollectionReusableView,UICollectionViewCell : UICollectionReusableView
UIKIT_EXTERN NSString *const UICollectionElementKindSectionHeader NS_AVAILABLE_IOS(6_0);
UIKIT_EXTERN NSString *const UICollectionElementKindSectionFooter NS_AVAILABLE_IOS(6_0);
UIKIT_EXTERN const CGSize UICollectionViewFlowLayoutAutomaticSize NS_AVAILABLE_IOS(10_0);
复制代码
注册supplementary view时,还需要额外指定一个称为类型字符串kind string的附加标志符。
layout负责定义各自支持的补充视图种类。例如,UICollectionViewFlowLayout支持两种补充视图:section header、section footer。为了识别这两种类型视图,flow layout定义了UICollectionElementKindSectionHeader和UICollectionElementKindSectionFooter字符串常量。
在布局时,集合视图将包括类型字符串和其它布局属性的layout发送给数据源,数据源使用类型字符串kind string和重用标志符reuse identifier决定出列视图
复制代码

---这些api详解都少了Drag & Drop--

标准的UICollectionView包含三个部分,它们均需要是UICollectionReusableView的子类:
1. Cells 用于展示内容的主体,对于不同的cell可以指定不同尺寸和不同的内容,这个稍后再说
2. Supplementary Views 追加视图 如果你对UITableView比较熟悉的话,可以理解为每个Section的Header或者Footer,用来标记每个section的view
3. Decoration Views 装饰视图 这是每个section的背景,比如iBooks中的书架就是这个
typedef NS_ENUM(NSUInteger, UICollectionElementCategory) {
    UICollectionElementCategoryCell,
    UICollectionElementCategorySupplementaryView,
    UICollectionElementCategoryDecorationView
};
复制代码
1. UICollectionViewLayoutAttributes : NSObject
定义一些frame、size、transform等基础布局信息属性

2. UICollectionViewUpdateItem : NSObject
An object that describes a ***single change*** to make to **an item** in a collection view.
You do not create instances of this class directly. 
When updating its content, the collection view object creates them and passes them to the layout object’s “prepareForCollectionViewUpdates: method”, 
which can use them to prepare the layout object for the upcoming changes.

当collection view的数据源发生插入、删除、移动变化时,UICollectionView会创建UICollectionViewUpdateItem类的实例,
并发送给layout的prepareForCollectionViewUpdates:方法,layout会为即将到来的布局变化作出准备。你不需要创建该类的实例。

3. UICollectionViewLayoutInvalidationContext : NSObject

当UICollectionView调用invalidateLayoutWithContext:方法重新布局的时候配置该参数,指定哪些cell需要重新布局,
invalidateLayoutWithContext方法使原来的layout失效
通过Invalidation Context指明布局发生改变的部分,使那些布局真正发生改变的部分无效来提升布局性能。

当你自定义一个UICollectionViewLayout子类时,你可以调用invalidationContextClass方法来返回一个你定义的UICollectionViewLayoutInvalidationContext的子类,
这样你的Layout子类在失效时会使用你自定义的InvalidationContext子类来优化更新布局。

4. UICollectionViewLayout : NSObject
5. UICollectionViewLayout (UISubclassingHooks)
6. UICollectionViewLayout (UIUpdateSupportHooks)
7. UICollectionViewLayout (UIReorderingSupportHooks)
复制代码
UICollectionViewLayout
UICollectionViewLayout有3个分类,它们的大概作用如下:
@interface UICollectionViewLayout (UISubclassingHooks) 这个扩展类中,都是用来布局UIcollectionView子视图的
@interface UICollectionViewLayout (UIUpdateSupportHooks) 用来布局删除插入动作
@interface UICollectionViewLayout (UIReorderingSupportHooks) 移动动作布局

在更新数据源时,按照以下步骤操作:
1. 更新数据源中数据。
2. 调用UICollectionView方法进行插入、删除、移动section或item操作。

UICollectionViewLayout可以说是UICollectionView的大脑和中枢,****它负责了将各个cell、Supplementary View和Decoration Views进行组织,为它们设定各自的属性****,包括但不限于:
位置
尺寸
透明度
层级关系
形状
等等等等…
Layout决定了UICollectionView是如何显示在界面上的。在展示之前,一般需要生成合适的UICollectionViewLayout子类对象,并将其赋予CollectionView的collectionViewLayout属性。
复制代码

---Drag & Drop部分 UICollectionView (UIDragAndDrop)---

跨 App 的 Drag and Drop 只能在 iPad 上使用,iPhone 只支持 App 内的 Drag and Drop。

iOS 11增加了系统范围的拖放操作drag and drop,让用户可以快速简单的将文本、图像和文件从一个app移动到另一个app,
只需轻点并按住即可提取其内容,拖放到其它位置。
复制代码

----上面API部分,下面为使用----

UIDragItem、UIDragSession、UIDropSession、UIDragInteraction、UIDropInteraction

Drag 的对象是我们平时所接触的 UI 控件,UILabel,UIImageView,或者自定义的 View。让控件可拖动,只需要给控件添加 UIDragInteraction 对象

单指长按某个 View 时,如果添加了 UIDragInteraction,Drag 即刻启动,进入 itemsForBeginningSession 的回调,
这个方法中出现的三个类,关系也十分简单。一个 UIDragInteraction 可以包含多个 UIDragSession,每个 UIDragSession 又可以包含多个 UIDragItem。
UIDragItem 则是 Drop 时接收方所受到的对象。

UIDragItem 包含一个 NSItemProvider 对象,NSItemProvider 对象则包含一个 id<NSItemProviderWriting> 对象。
protocol NSItemProviderWriting 则定义了 UIDragItem 中所包含的数据最后以何种形式提供个 Drop 方
复制代码

4. UIPageControl、UIPageViewController
PageViewController像电子书那样,一页之中可以放几个childViewcontroller,  然后左右翻,当前frame显示几个viewcontroller。

UIPageControl配合scrollView是用于左右滑动翻页的,当前frame只显示一个viewcontroller。
复制代码

5. UINavigationBar、UIBarButtonItem、UIToolbar、UINavigationItem、UINavigationController
UINavigationController(导航控制器)是一个容器控制器,其内部展示着多个UIViewController(视图控制器)的内容, 
我们可以通过UINavigationController的view属性获取到其自身的视图,
在该视图上有一个位于界面顶部的UINavigationBar(导航栏)和位于界面底部的默认隐藏的UIToolbar(工具栏), 以及一个位于界面中间部分的UIViewController的view

UINavigationController负责创建、配置及管理UINavigationBar,
其通过位于UIViewController堆栈栈顶位置的UIViewController的navigationItem属性(该属性位于UIViewController的UINavigationControllerItem类目中)来管理UINavigationBar展示的内容, 
同时UINavigationController也提供了navigationBar属性, 允许开发者通过该属性设置UINavigationBar的外观

UINavigationBar设置navigationBar的外观,UINavigationItem设置UINavigationBar展示的内容

// 侧滑返回手势识别器
@property(nonatomic, readonly) UIGestureRecognizer *interactivePopGestureRecognizer;

复制代码
在 Navigation 集成 UISearchController
把你的UISearchController赋值给navigationItem,就可以实现将UISearchController集成到 Navigation.
复制代码
6. UITabBarController、UITabBar、UITabBarItem
UITabBarController和UINavigationController一样是用来管理试图控制器的,
与导航控制器不同,tabBarController控制器使用数组管理子试图控制器的,并且子试图之间是平等关系,
导航控制器所管理的试图控制器之间是在出桟和入桟的关系;
复制代码
7. UISearchBar、UISearchContainerViewController、UISearchController、UISearchDisplayController
UISearchBar的视图层次结构:
<UISearchBar: 0x7fb6586b6ca0; frame = (10 30; 355 30); text = ''; tintColor = UIDeviceRGBColorSpace 1 0.5 0 1; gestureRecognizers = <NSArray: 0x7fb6586bab20>; layer = <CALayer: 0x7fb658609540>>
   | <UIView: 0x7fb6586b9e00; frame = (0 0; 355 30); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x7fb65869f110>>
   |    | <UISearchBarBackground: 0x7fb6586baff0; frame = (0 0; 355 30); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7fb6586bb4c0>>
   |    | <UISearchBarTextField: 0x7fb658525ce0; frame = (0 0; 0 0); text = ''; clipsToBounds = YES; opaque = NO; layer = <CALayer: 0x7fb658505960>>
   |    |    | <_UISearchBarSearchFieldBackgroundView: 0x7fb658419960; frame = (0 0; 0 0); opaque = NO; autoresize = W+H; userInteractionEnabled = NO; layer = <CALayer: 0x7fb658409dc0>>

复制代码
** UISearchController是iOS 8** 之后推出的一个新的控件, 用于创建搜索条, 及管理搜索事件, 
使用这个, 我们可以很容易的创建属于自己的搜索框, 
复制代码
8.需要知道的其它控件
iOS8.0开始推荐使用UIPopoverPresentationController,用于替代UIPopoverController。
UIPopoverPresentationController的使用方法类似于UIPopoverController,但是前者可以同时在iPhone和iPad上使用,这一点很不错。
UIPopoverPresentationController并不是控制器类,而是继承自NSObject,不能直接被弹出
复制代码
Socket(GCDAsyncSocket、WebSocket、SIOSocket)
Git、SVN、CocoaPods

---CocoaPods---

----Git-----

1.集中式工作流
小红:
     ssh user@host
     git init --bare /path/to/repo.git
     git status # 查看本地仓库的修改状态
     git add # 暂存文件
     git commit # 提交文件
     git push origin master
小黑:
     git clone ssh://user@host/path/to/repo.git
     git status # 查看本地仓库的修改状态
     git add # 暂存文件
     git commit # 提交文件
     git pull --rebase origin master
     git push origin master
如果有冲突:
     git add <some-file> 
     git rebase --continue
     git push origin master
冲突解决不了:
     git rebase --abort

2.功能分支工作流
小明:
     git checkout -b marys-feature master
     git status
     git add <some-file>
     git commit
     git push origin marys-feature
     在Git GUI发起一个Pull Request
其他人同意向master push
     git checkout master #切换回master
     git pull #拉取当前master确认最新
    #pull == fetch+merge
     git pull origin marys-feature #将marys-feature分支合并到master
     git push origin master #push到中央仓局master
    
3.Gitflow工作流
#历史分支
Gitflow工作流使用两个分支来记录项目的历史。master分支存储了正式发布的历史,而develop分支作为功能的集成分支。
#功能分支
每个新功能位于一个自己的分支,这样可以push到中央仓库以备份和协作。
但功能分支不是从master分支上拉出新分支,而是使用develop分支作为父分支。当新功能完成时,合并回develop分支。 新功能提交应该从不直接与master分支交互。
#发布分支
一旦develop分支上有了做一次发布(或者说快到了既定的发布日)的足够功能,就从develop分支上checkout一个发布分支。
新建的分支用于开始发布循环,所以从这个时间点开始之后新的功能不能再加到这个分支上—— 这个分支只应该做Bug修复、文档生成和其它面向发布任务。
一旦对外发布的工作都完成了,发布分支合并到master分支并分配一个版本号打好Tag。 另外,这些从新建发布分支以来的做的修改要合并回develop分支。

使用一个用于发布准备的专门分支,使得一个团队可以在完善当前的发布版本的同时,另一个团队可以继续开发下个版本的功能。
这也打造定义良好的开发阶段(比如,可以很轻松地说,『这周我们要做准备发布版本4.0』,并且在仓库的目录结构中可以实际看到)
#维护分支
维护分支或说是热修复(hotfix)分支用于给产品发布版本(production releases)快速生成补丁,这是唯一可以直接从master分支fork出来的分支。
修复完成,修改应该马上合并回master分支和develop分支(当前的发布分支),master分支应该用新的版本号打好Tag
#示例
     太多了不写了:注意发布分支release和hotfix分支与master和develop分支合并后删除
     Gitflow工作流中Pull Request的使用过程:
     当一个功能、发布或是热修复分支需要Review时,开发者简单发起一个Pull Request, 团队的其它成员会通过Bitbucket收到通知。
     新功能一般合并到develop分支,而发布和热修复则要同时合并到develop分支和master分支上。 Pull Request可能用做所有合并的正式管理。

4.Forking工作流

Forking工作流是分布式工作流,充分利用了Git在分支和克隆上的优势。可以安全可靠
地管理大团队的开发者(developer),并能接受不信任贡献者(contributor)的提交。

Forking工作流和前面讨论的几种工作流有根本的不同,这种工作流不是使用单个服务端仓库作为『中央』代码基线,而让各个开发者都有一个服务端仓库。
这意味着各个代码贡献者有2个Git仓库而不是1个:一个本地私有的,另一个服务端公开的。

Forking工作流的一个主要优势是,贡献的代码可以被集成,而不需要所有人都能push代码到仅有的中央仓库中。
开发者push到自己的服务端仓库,而只有项目维护者才能push到正式仓库。 这样项目维护者可以接受任何开发者的提交,但无需给他正式代码库的写权限。

其他贡献者fork正式仓库代码,修改后提交到自己的仓库中,给正式仓库发起一个pull request,维护者同意后会push到正式仓库

复制代码

---SVN---

---Git、SVN异同----

Linux
  • []
杂项
越狱开发+反编译

RAC
1. 'RACSiganl:RACStream':信号类,只是表示当数据改变时,信号内部会发出数据,它本身不具备发送信号的能力,而是交给内部一个订阅者去发出。
2. 'RACSubscriber':表示订阅者的意思,用于发送信号,这是一个协议,不是一个类,只要遵守这个协议,并且实现方法才能成为订阅者。通过create创建的信号,都有一个订阅者,帮助他发送数据。
3. 'RACSubject' : RACSignal<RACSubscriber>:信号提供者,由于继承RACSignal(信号类)+实现接口RACSubscriber(订阅者),所以自己可以充当信号,又能发送信号
------
'冷热信号':
冷信号是被动的,只会在被订阅时向订阅者发送通知;热信号是主动的,它会在任意时间发出通知,与订阅者的订阅时间无关。
也就是说冷信号所有的订阅者会在订阅时收到完全相同的序列;而订阅热信号之后,只会收到在订阅之后发出的序列。
热信号的订阅者能否收到消息取决于订阅的时间。

在 ReactiveCocoa 中,我们使用RACSignal来表示冷信号,也就是每一个订阅者在订阅信号时都会收到完整的序列;RACSubject用于表示热信号,订阅者接收到多少值取决于它订阅的时间。


RACSubject 的实现并不复杂,它『可变』的特性都来源于持有的订阅者数组 subscribers,在每次执行 subscribeNext:error:completed: 一类便利方法时,都会将传入的 id<RACSubscriber> 对象加入数组:
RACSubject 会在自身接受到这些方法时<RACSubscriber>协议中的方法,下发给持有的全部的 subscribers。

RACBehaviorSubject 和RACReplaySubject,前者在订阅时会向订阅者发送最新的消息,后者在订阅之后可以重新发送之前的所有消息序列。

4. 'RACBehaviorSubject'最重要的特性就是在订阅时,'向最新的订阅者发送之前的最新消息',这是通过覆写 -subscribe: 方法实现的。
RACBehaviorSubject,它在内部会保存一个currentValue对象,也就是最后一次发送的消息:
在每次执行 -sendNext: 时,都会对 RACBehaviorSubject 中保存的 currentValue 进行更新,并使用父类的 -sendNext: 方法,向所有的订阅者发送最新的消息 

5. 'RACReplaySubject' 相当于一个自带 buffer 的 RACBehaviorSubject,它可以在每次有新的订阅者订阅之后发送之前的全部消息。

6. 'RACTuple':元组类,类似NSArray,用来包装值.

7. 'RACSequence:RACStream':RAC中的集合类,用于代替NSArray,NSDictionary,可以使用它来快速遍历数组和字典。
[numbers.rac_sequence.signal subscribeNext:^(id x) {
       
        NSLog(@"%@",x);
    }];

8. 'RACCommand:NSObject':RAC中用于处理事件的类,可以把事件如何处理,事件中的数据如何传递,包装到这个类中,他可以很方便的监控事件的执行过程。

9. 'RACMulticastConnection:NSObject':用于当一个信号,被多次订阅时,为了保证创建信号时,避免多次调用创建信号中的block,造成副作用,可以使用这个类处理。
 **订阅connect.signal,会调用RACSubject的subscribeNext,创建订阅者,而且把订阅者保存起来,不会执行block。**

10. RACScheduler:RAC中的队列,用GCD封装的

11. RACUnit :表⽰stream不包含有意义的值,也就是看到这个,可以直接理解为nil.

12. RACEvent: 把数据包装成信号事件(signal event)。它主要通过RACSignal的-materialize来使用,然并卵。


13 . 处理当界面有多次请求时,需要都获取到数据时,才能展示界面
'rac_liftSelector:withSignalsFromArray:Signals:'当传入的Signals(信号数组),每一个signal都至少sendNext过一次,就会去触发第一个selector参数的方法。
使用注意:几个信号,参数一的方法就几个参数,每个参数对应信号发出的数据。

复制代码
大侠博客
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值