ios学习

作者: 夺光 | 来源:发表于2018-01-24 11:59 被阅读101次

    1、内存管理:

    __weak 只是把只地址取得 放到以变量为key的哈希表里面 进行若引用的存储,对原有对象是没有影响的 ,

    2、循环引用

    一般arc下,直接__weak可以阻断循环引用,在mrc下__block阻断循环引用的发生 原因是__block在arc下是不增加引用计数的 所以可以达到这一目的,在arc下如果也要使用__block达到这个效果 需要在block体里面进行制空,释放强引用,这样才可以做到解除循环引用。关于制空为什么会解除强引用 ,是因为在arc下__strong变量,当没有任何人持有的时候,这时候会被废弃。

    3、GCD  :dispatch_sync或者dispatch_async 只是对于处理的结果是否保持同步或者异步,sync是要等待处理结果的,async不需要等待;serial queue只是说明当前队列是串行执行,concurrent queue是系统帮助管理多线程的处理操作,并不见得是由一个线程来处理。所以总结一下,一个是面向结果是否等待,一个是面向如何处理任务。

    4、坐标系转换样例

    // controllerA 中有一个UITableView, UITableView里有多行UITableVieCell,cell上放有一个button// 在controllerA中实现:receiver 也就是调用者是将要转换的view的父视图。CGRect rc = [cell convertRect:cell.btn.frame toView:self.view];或CGRect rc = [self.view convertRect:cell.btn.frame fromView:cell];

    5、动态方法解析与消息转发:如果以上的类中没有找到对应的selector(一般保险起见先用respondsToSelector:内省判断):,还可以利用消息转发机制依次执行以下流程:     Method Resolution(动态方法解析):用所属类的类方法+(BOOL)resolveInstanceMethod:(实例方法)或者+(BOOL)resolveClassMethod:(类方法),在此方法里添加class_addMethod函数。一般用于@dynamic动态属性。(当一个属性声明为@dynamic,就是向编译器保证编译时不用管/get实现,一定会在运行时实现)。

    Fast Forwarding (快速消息转发):如果上一步无法响应消息,调用- (id)forwardingTargetForSelector:(SEL)aSelector方法,将消息接受者转发到另一个对象target(不能为self,否则死循环)。

    Normal Forwarding(普通消息转发):如果上一步无法响应消息:调用方法签名- (NSMethodSignature )methodSignatureForSelector:(SEL)aSelector,方法签名目的将函数的参数类型和返回值封装;如果返回非nil,则创建一个NSInvocation对象利用方法签名和selector封装未被处理的消息,作为参数传递给- (void)forwardInvocation:(NSInvocation)anInvocation。这一步比较耗时。

    简单的说消息转发,就是3种,1添加一个方法。2让某个对象去接消息。3创造一个方法签名,然后让其他对象去接。

    Fast Forwarding (快速消息转发):如果上一步无法响应消息,调用- (id)forwardingTargetForSelector:(SEL)aSelector方法,将消息接受者转发到另一个对象target(不能为self,否则死循环)。

    Normal Forwarding(普通消息转发):如果上一步无法响应消息:调用方法签名- (NSMethodSignature )methodSignatureForSelector:(SEL)aSelector,方法签名目的将函数的参数类型和返回值封装;如果返回非nil,则创建一个NSInvocation对象利用方法签名和selector封装未被处理的消息,作为参数传递给- (void)forwardInvocation:(NSInvocation)anInvocation。这一步比较耗时。

    6、+load方法和+initialize方法。load方法是首次加载类时调用,绝对只调用一次;initialize方法是首次给类发消息时调用,通常只调用一次,但如果它的子类初始化时未定义initialize方法,则会再调用一次它的initialize方法

    7、实现类似京东下拉刷新(小人快跑)动画,主要是通过shapelayer设置path,path怎么得到是画出来还是勾勒出来不考虑,最核心的是通过strokestart和strokeend进行设置的,下面直接说start和end代称,讲解一下start和end都是干嘛的:画出path指定开始的path位置和结束path的位置,中间的path才是我们画出来的,所以我们可以做一个在动的动画,就是控制path绘制的显示来让动画显示出来的。

    8、viewdidappear是在过场动画结束后被调用 过场动画的时间是0.35秒

    9、[view setExclusiveTouch:YES]; 这属性的作用是同一个view内 用来防止多个点同时触摸

    10、Content Hugging Priority控制当view frame>intrinsicContentSize时,是不是要缩小view 的size,此constraint试图保持view的size不让其变大;而Content Compression Resistancy Priority控制当view frame<intrinsicContentSize时, 要不要截断content,保持view frame size。 实际尺寸比设定尺寸大的时候才会去考虑压缩优先级,实际尺寸比设定尺寸小的时候才会去考虑拥抱优先级,此constraint试图保持view的size不让其变小。这两个属性都是针对于intrinsiccontentsize,都是对于intrinsiccontentsize进行的操作。由此理解约束最后都会去确认intrinsiccontentsize是否可以缩小,这样的布局方式。

    11、关于copy是否会增加引用计数的问题,这个主要是要说一下所copy的对象的copywithzone函数和mutablecopywithzone函数的实现,是否会造成引用计数的增加,比如系统的nsarray和nsmutablearray,两者使用copy的时候,nsarray只是简单的增加引用计数并返回,而nsmutablearray却会重新构建一个对象返回回去,所以nsmutablearray copy 就不会增加引用计数,而当调用mutablearray的时候,nsarray和nsmutablearray都会构建一个新的nsmutablearray对象返回回去,所以copy是否增加引用计数是要看具体协议实现的。

    12、关于runtime,先说变为可执行文件的过程,预编译-编译-汇编-链接=>可执行文件,那么我们分辨看一下每一步的产物,预编译是在做宏替换等操作,然后编译在oc会先由clang把oc代码变为一个语句树,这个语句树标识着每一段都是干什么用的,然后llvm根据语句树转译成为汇编语言,然后汇编器把汇编语言转译成机器语言,得到的是一个目标文件,然后进行链接,连接器主要就是把一些文件的undfind的”空白区域“进行填补,然后把静态库也链接进来,最终把这些拷贝到一个文件里面,这就是可执行文件。总体上目标文件和可执行文件结构差不多,这里说一下目标文件,目标文件里面有机器指令码、数据、符号表、调试信息、字符串等,会以segment的形式进行存储,机器指令码存放在代码段,全局变量、静态变量存放在数据段,机器指令码其实就是所写的代码,关于全局变量静态变量还有函数地址是何时确定的问题,是在编译器知道偏移量,然后编译完以后,链接器开始链接编译后的文件,确定每个文件的段地址,段地址+偏移量来确定的具体变量的地址,要说的是这些地址在开始加载程序的时候,内存映射的地址是一样的!!!,局部变量的地址是靠对应的函数栈的汇编操作来确定的。还有就是编译的时候,有些外联的变量无法确定偏移地址,编译器就会导出一个重定向表,这个由编译器去处理,所以编译会导出确定表、非确定表、重定向表。

    13、self和super 调用class区别:super会调用obj_msgsuper ,target是一个结构体,里面是当前对象和superclass,调用的时候去寻找superclass的方法,但是没找到,去找nsobject里面的,找到后用结构体的第一个元素去调用,也就是当前对象去调用,所以输出就是子类;相应的如果在父类里面能找到方法,那么就直接调用,而子类调用父类的方法,这个过程就是方法调用的过程。为何这样究其原因接收消息的实体一直都是一个,也就是当前对象。我觉得msgsuper和msg的区别就是不用去当前类里面去寻找了,而是直接就去父类寻找,哈哈。

    14、ios内存组织结构,在链接后确认的代码段数据段的内容,在运行的时候会有局部变量,这个就是堆栈里面放置,要明确的是栈的生长方向是高到低,堆的生长方向是低到高;

    15、关于下载任务多线程和单线程哪个快的问题,如果线程下载任务能达到网卡上限得话,单线程和多线程没有太多性能差距,但现实中很少能达到网卡瓶颈,所以一个下载资源只能用到一部分带宽,而多线程的话就可以尽可能的占用带宽,所以多线程的速度要快。说白了就是单位时间内使用的带宽越多速度越快,而多线程就是增加了占用的带宽。以上理解的有问题,但是不失为一种理解的过程,其实底层已经使用kqueue做了异步io,不管是并发还是串行的任务都会由内核进行数据的io操作,这时候只分阻塞还是非阻塞两种方式,阻塞的时候就是等待任务完成,非阻塞就是何时io缓存里面有数据就继续处理,没有了就停止等有了数据再次进行处理,这也就是咱们理解的同步与异步,值得说的这里的阻塞是指接收这一端的操作,而不是发送那一端的阻塞。

    16、总结一下线程相关的感悟,先说进程的作用,计算机运行的时候会分出很多进程,进程包含代码和资源,cpu就会处理代码,可以猜想一下,进程没有出现之前,所有的代码和资源都放在一起,这样如果是多个应用不能把代码都放到一起吧?所以说进程的目的就是代码分离和资源的隔离,还有一个就是如果要做很多任务,那么就需要多进程来进行处理。那线程的目的也是类似,在手机端,ui主线程里面执行读取文件操作,那么主线程就要被卡住了,所以说要多个线程来做异步,把耗时操作放到其他线程,所以说多个任务还要一起执行多线程是一个很好的办法!再看http请求,要说一个命题:http请求会启动线程去处理。为何要这么说呢?因为http请求很明显是一个耗时的操作,如果在ui线程进行网络请求势必要使用while循环来不间断获取response.data,很明显ui线程会被卡住,所以http请求就要就要异步的去进行处理。更多的说一下系统的api,cfnetwork或者socket来做处理的时候不会自己去创建线程(因为网络请求是网络请求,线程是线程,只不过网络请求是一个耗时操作,不想卡住当前线程,所以才会使用异步来做处理),而系统的urlsession、URLHTTPconnect内部已经封装了线程的异步处理,所以说呢 多线程就真的是想做任务而存在的,与网络请求或者文件读取是没关系的。

    17、弱引用的实现结构 是一个weaktable里面存放着weakentry数组,而这个数组的entry是通过index寻找的,这个index是通过掩码计算的hash值,寻找到的entry其实就是这个newobj所对应的散列表,所以这就能看出来是散列表套散列表的数据结构。那么创建弱引用对象的时候,就是查看是否存在对应的entry如果没有在table->entrys里insert一个entry并查看是否需要grow这个散列表,这个entry是一个散列表,里面存储的是弱引用的指针;删除弱引用的时候,就把对应的entry里面的弱引用置为nil,并减少计数范围,并且判断这个entry是否为empty,如果是空的就删除这个entry。当newobj销毁的时候,当调用dealloc的时候,里面会有一个weakclear方法,就会把newobj对应的entry的弱引用置为nil,并且删除掉entry。

    相关文章

      网友评论

          本文标题:ios学习

          本文链接:https://www.haomeiwen.com/subject/vtxuaxtx.html