美文网首页
iOS 一些比较重要的知识点

iOS 一些比较重要的知识点

作者: HuaJianDev | 来源:发表于2017-09-06 18:02 被阅读9次

    一.UITableView的Cell重用机制

    1.传统重用机制
    - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    //   ① .定义一个重用标识符,用static修饰。就放在了内存的静态区了。
        static NSString *reuseID = @"A";
    
    //    ②.缓存池中寻找是否有可以重用的cell
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseID];
    
    //    ③.如果从缓存池中没有找到cell,创建一个cell,并给它一个重用标识符
        if (cell == nil) {
            cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseID];
        }
    
    //    填充数据,赋值给cell
    
        return cell;
    }
    
    2.注册机制的重用

    从iOS 6.0开始,添加了缓存池的优化方法
    ①.先去缓存池中寻找指定标识符的cell,是否存在可以重用的cell
    ②.如果缓存池中没有,按照提前注册的方式自动创建一个cell,并打上标识符。
    ③.往cell上填充数据

    注册cell的三种方式
    • 用XIB的方式注册一个cell,并设置复用标识符。如果tableView需要显示一个cell,会加载复用标识符指定的xib来自动创建需要的cell。
    //一般在viewDidLoad中注册
    [_tableView registerClass:[ClassName class] forCellReuseIdentifier:@"reuseID"];
     //ClassName 要注册的cell的类名
    //ReuseID 复用标识符
    
    • 通过类方法来注册cell,并设置重用标识符。如果tableView需要显示一个cell,会加载服用标识符指定的类来自动创建cell。
    //一般在viewDidLoad中注册
    [_tableView registerNib:[UINib nibWithNibName:@"ClassName" bundle:nil] forCellReuseIdentifier:@"reusedID"];
     //ClassName 要注册的cell的类名
    //ReuseID 复用标识符
    
    • 通过storyboard来注册cell,并设置复用标识符。(在storyboard界面的属性里的Identifier项设置复用标识符)

    二.ARC的原理

    ARC的原理是在编译器为每一个对象加入合适的代码,以期保证这些对象有合理的生命周期。从概念上来说,ARC通过增加retain、release、autorelease等函数,使得在维护内存计数器方面达到和手动管理内存同样的效果。

    三.如何避免retain cycle

    retain cycle问题的根源在于Block和obj可能会互相强引用,互相retain对方,这样就导致了retain cycle,最后这个Block和obj就变成了孤岛,谁也释放不了谁。解决这个问题的办法是使用弱引用打断retain cycle。

    四.对MVC的理解

    M:Model 数据模型(模型)
    V:View用户界面(视图)
    C:Controller控制器(控制器)

    使用MVC的目的是实现M和V的代码分离,从而使同一个程序可以使用不同的表现形式。

    MVC是如何通信的?

    Controller -> Model

    Controller 对 Model有完全访问权限。

    Model -> Controller

    Model 通过 Notification & KVO的方式与Controller通信。

    Controller -> View

    Controller 对 View 也有完全的访问权限。如:Controller拥有一个outlet属性,该属性指向View中的对象。

    View -> Controller

    View 通过 action-target 的方式与Controller通信。如:button的点击
    View 还通过 Delegate 的方式与Controller通信。
    数据不能作为视图的内部属性。它是通过 data source delegate的方式与Controller通信的。也就是说,Controller从Model中获取数据然后传递给View。

    Model <-> View

    Model和View不能相互通信。是完全独立的。

    五.iOS内存管理机制

    iOS内存管理机制的原理是引用计数,引用计数简单来说就是统计一块内存的所有权,当这块内存被创建出来的时候,它的引用计数从0增加到1,表示有一个对象或指针持有这块内存,拥有这块内存的所有权,如果这时候有另外一个对象或指针指向这块内存,那么为了表示这个后来的对象或指针对这块内存的所有权,引用计数加1变为2,之后若有一个对象或指针不再指向这块内存时,引用计数减1,表示这个对象或指针不再拥有这块内存的所有权,当一块内存的引用计数变为0,表示没有任何对象或指针持有这块内存,系统便会立刻释放掉这块内存。

    在开发时引用计数又分为ARC(自动内存管理)和MRC(手动内存管理)。ARC的本质其实就是MRC,只不过是系统帮助开发者管理已创建的对象或内存空间,自动在系统认为合适的时间和地点释放掉已经失去作用的内存空间,原理是一样的。虽然ARC操作起来很方便,不但减少了代码量,而且降低了内存出错的概率,但因为ARC不一定会及时释放,所以程序有时候可能会占用内存较大。而MRC若做得好,通过手动管理,及时释放掉不需要的内存空间,便可保证程序长时间运行在良好状态上。

    在MRC中会引起引用计数变化的关键字有:alloc,retain,copy,release,autorelease。(strong关键字只用于ARC,作用等同于retain)

    alloc:当一个类的对象创建,需要开辟内存空间的时候,会使用alloc,alloc是一个类方法,只能类调用,它的作用是开辟一块新的内存空间,并使这块内存的引用计数从0增加到1。注意,是新的内存空间,每次用类alloc出来的都是一块新的内存空间,与上一次alloc出来的内存空间没有必然联系,而且上一次alloc出来的内存空间仍然存在,不会被释放。

    retain:retain是一个实例方法,只能由对象调用,它的作用是使这个对象的内存空间的引用计数加1,并不会新开辟一块内存空间,通常于赋值时调用,如:

    对象2 = [对象1 retain]; //表示对象2通用拥有这块内存的所有权
    //若只是简单的赋值,如:
    对象2 = 对象1; //那么对象1的内存空间被释放的时候,对象2便会成为野指针,再对对象2进行操作便会造成内存错误。

    copy:copy同样是一个实例方法,只能由对象调用,返回一个新的对象,它的作用是赋值一个对象到一块新的内存空间上,旧内存空间的引用计数不会变化,新的内存空间的引用计数从0增加到1,也即是说,虽然内容一样,但实质上是两块内存,相当于克隆,一个变成两个。其中copy又分为浅拷贝、深拷贝和真正的深拷贝,浅拷贝只是拷贝地址,与retain等同;深拷贝是拷贝内容,会开辟新内存,与retain不一样;真正的深拷贝是对于容器类来说的,如数组类、字典类和集合类(包括可变和不可变),假设有一个数组类对象,普通的深拷贝会开辟一块新内存存放这个对象,但这个数组对象里面的各个元素的地址却没有改变,也就是说数组元素只是进行了retain或者浅拷贝而已,并没有创建新的内存空间,而真正的深拷贝,不但数组对象本身进行了深拷贝,连数组元素都进行了深拷贝,即为各个数组元素开辟了新的内存空间。

    release:realease是一个实例方法,同样只能由对象调用,它的作用是使对象的内存空间的引用计数减1,若引用计数变为0,则系统会立刻释放掉这块内存。如果引用计数为0的基础上再调用release,便会造成过度释放,使内存崩溃。

    autorelease:autorelease是一个实例方法,同样只能由对象调用,它的作用于release类似,但不是立刻减1,相当于一个延迟的release,通常用于方法返回值的释放,如遍历构造器。autorelease会在程序走出自动释放池时执行,通常系统会自动生成自动释放池(即使是MRC下),也可以自己设定自动释放池,如:

    @autoreleasepool{ 
      obj = [NSObject alloc] init];
      [obj autorelease];
    }
    

    当程序走出“}”时obj引用计数就会减1.

    除了以上所述的关键字,还有一些方法会引起引用计数的变化,如UI中父视图添加、移除子视图、导航控制器或视图控制器推出新的视图控制器以及返回,容器类(数组、字典和集合)添加和移除元素。

    当子视图添加到父视图上时子视图的引用计数加1,移除时引用计数减1,若父视图引用计数变为0内存被释放,其所有的子视图都会被release一次,即引用计数减1,原则上只有这三种情况子视图的引用计数会发生变化,其他如父视图引用计数的加减都不会影响到子视图。

    容器类的情况与视图类似,添加元素,该元素引用计数加1,移除元素,该元素引用计数减1,容器引用计数变为0所占用内存被释放,容器所有元素release,引用计数减1,其他情况下容器本身的引用计数变化不会影响到容器内元素的引用计数变化。

    导航控制器或视图控制器推出新的视图控制器会使被推出的视图控制器的引用计数加1,该视图控制器返回的时候引用计数减1。

    应注意:当一个对象的引用计数变为0占用内存被释放时,会调用- (void)dealloc方法,所以如果在MRC下自定义类,必须在该方法里将该类中属性关键字设置为retain或copy的属性release一次,以免造成内存泄露,重写方法不要忘记在第一行添加[super dealloc];

    相关文章

      网友评论

          本文标题:iOS 一些比较重要的知识点

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