• [Objective-c 基础


    A.内存存放、retain、release

    1.栈内存:存放局部变量,运行超过变量作用域自后编译器自动回收
    2.堆内存:存放对象(地址,对象实体)
    3.对象的基本结构
    (1)引用计数器(4字节):当计数器为0的时候被回收,初始化时为1
    (2)当使用alloc、new、copy创建对象的时候,计数器默认是1
    (3)给对象发送一条retain消息,计数器+1
    (4)给对象发送一条release消息,计数器-1
    (5)给对象发送一条retainCount,返回计数器数值
    (6)对象被回收的时候,会调用dealloc方法;一般会重写dealloc方法,并最后调用[supper dealloc]
    1 //当一个Person对象被系统回收的时候,就会调用此方法
    2 - (void) dealloc
    3 {
    4    NSLog(@"Person对象被回收");
    5     [superdealloc];
    6 }
     
    4.野指针错误(运行时错误)EXC_BAD_ACCESS
    对象被回收之后,继续使用指针release对象,实际指针指向的对象已经不存在了(指向不可用内存)
    解决:回收对象之后,清空指针,p = nil;
    给空指针发送消息不会报错
    OC中不存在空指针错误
     
    5.僵尸对象管理 Zombie Object
    不开启XCode中OC的Zombie Object管理的时候,对野指针调用对象方法、retainCount不会报错,计数器自动变回1
    1     //0
    2     [prelease];
    3    
    4     p.age=11;
    5     [prun];
    开启之后会发生运行时错误BAD_BREAKPOINT
    开启方法:运行项目 -> Edit Scheme -> Diagnostic -> Enable Zombie Objects
     
    概念:
    (1)僵尸对象:所占内存已经被回收的对象,僵尸对象不能再用
    (2)野指针:指向僵尸对象(不可用内存)的指针,给野指针发送消息会发送BAD_ACCESS运行时错误
    (3)空指针:没有指向任何东西的指针(存储的时nil、NULL、0),给空指针发送消息不会报错
     
    6.对象setter方法内存管理
    (1)谁创建,谁release
    (2)谁retain,谁release
    (3)类的对象成员变量,在setter中retain,在dealloc中release
    a.Person类声明
    1 @interfacePerson :NSObject
    2 {
    3    Book*_book;
    4 }
    5 
    6 - (Book*) book;
    7 - (void) setBook:(Book*) book;
    8 
    9 @end
     
    b.Person类实现
     1 @implementationPerson
     2 - (Book*) book
     3 {
     4    return_book;
     5 }
     6 
     7 - (void) setBook:(Book*) book
     8 {
     9    if(_book!= book)
    10     {
    11         [_bookrelease];
    12     }
    13    _book= [bookretain];
    14 }
    15 
    16 - (void) dealloc
    17 {
    18     [_bookrelease];
    19    NSLog(@"Person被回收");
    20     [superdealloc];
    21 }
    22 
    23 @end
     
    c.main.c
     1 intmain(intargc,constchar* argv[]) {
     2    // b=1
     3    Book*b = [[Bookalloc]init];
     4    // p1=1
     5    Person*p1 = [[Personalloc]init];
     6    
     7    // b=2
     8     [p1setBook:b];
     9    
    10    // b=1
    11     [brelease];
    12     b =nil;
    13    
    14    // p1=0, b=0
    15     [p1release];
    16     p1 =nil;
    17    
    18    return0;
    19 }
     
     
    B.@property的内存管理
    1.使用@property默认生成的setter不会调用retain
     
    2.使用@property参数可以自动管理指针引用数
    例如retain:生成的setter自动retain一次,但是dealloc中的release还是需要手动编写
    ——————Peron.h-------------------
    1 @interfacePerson :NSObject
    2 @propertyintage;
    3 @property(retain)Book*book;
    4 
    5 @end
     
    —————Person.m--------------------
    1 @implementationPerson
    2 - (void) dealloc
    3 {
    4     [_bookrelease];
    5     [superdealloc];
    6 }
    7 @end
     
    3.@property的参数类型
    同一个类型的参数只能使用一个
    (1)内存管理相关参数
    a. retain:release旧值,retain新值(适用于OC对象类型),注意dealloc中要手动释放一次
    b. assign:直接赋值(默认,适用于非OC对象类型)
    c. copy:release旧值,copy新值
     
    (2)是否生成setter
    a. readwrite:同时生成setter和getter的声明、实现
    b. readonly:只会生成getter的声明、实现
    @property(readonly)floatheight;
     
    (3)多线程管理
    a. nonatomic:性能高(一般手动指定这种)
    b. atomic:性能低(默认)
    @property(nonatomic) int age;
     
    (4)setter和getter的名称,默认的setter、getter也有效
    @property(nonatomic,getter=abc,setter=setAbc:) int weight;
    注意写对setter方法,带冒号
     
        p.weight=10;//默认的setter
       NSLog(@"p.weight = %d", p.abc);
    out:
    p.weight = 10
     
     总结:
    *setter:增加setter的名称,一定要加上冒号
    *getter:增加getter的名称,一般用于增加BOOL类型的返回方法(is开头)
     
     
    C.循环retain
    1.循环声明
    使用#import引入所有类信息的时候,当两个类互相持有对方的对象作为成员变量的时候,会出现变异错误:类不能被识别
    ——————Person.h—————————
    1 #import<Foundation/Foundation.h>
    2 #import"Card.h"
    3 
    4 @interfacePerson : NSObject
    5 @property(nonatomic,retain) Card *card;
    6 @end
     
    —————Card.h--------------------------------
    1 #import<Foundation/Foundation.h>
    2 #import"Person.h"
    3 
    4 @interfaceCard :NSObject
    5 @property(nonatomic,retain)Person*person;
    6 @end
     
    解决:
    (1)使用@class声明一个类
    仅仅告诉编译器某个名称是个类,忽略类中的其他信息
    ——————Person.h—————————
    1 #import<Foundation/Foundation.h>
    2 
    3 @classCard;
    4 
    5 @interfacePerson :NSObject
    6 @property(nonatomic,retain)Card*card;
    7 @end
    —————Card.h--------------------------------
    1 #import<Foundation/Foundation.h>
    2 
    3 @classPerson;
    4 
    5 @interfaceCard : NSObject
    6 @property(nonatomic,retain) Person *person;
    7 @end
     
    (2).若需要使用成员类中的其他信息,可以再.m文件中再#import
    —>原则:在.m文件中才引入其他类的.h头文件
     
     
    2.循环retain
    互相持有,且使用了retain属性,不能释放
     1 intmain(intargc,constchar* argv[]) {
     2    Person*p = [[Personalloc]init];
     3    Card*c = [[Cardalloc]init];
     4     p.card= c;
     5     c.person= p;
     6    
     7     [prelease];
     8     [crelease];
     9    return0;
    10 }
     
    解决:其中一方使用retain属性,另一方使用assign手动进行回收
    ———Person.h-------------
    1 @implementationPerson
    2 - (void) dealloc
    3 {
    4    NSLog(@"Person被回收");
    5     [_cardrelease];
    6     [superdealloc];
    7 }
    8 
    9 @end
     
    ————Card.h--------------------
    1 #import<Foundation/Foundation.h>
    2 
    3 @classPerson;
    4 
    5 @interfaceCard :NSObject
    6 @property(nonatomic,assign)Person*person;
    7 @end
     
    ——————Person.m--------------
    1 @implementationPerson
    2 - (void) dealloc
    3 {
    4    NSLog(@"Person被回收");
    5     [_cardrelease];
    6     [superdealloc];
    7 }
    8 
    9 @end
     
    ———----------Card.m—————--
    1 @implementationCard
    2 - (void) dealloc
    3 {
    4    NSLog(@"Card被回收");
    5 //    [_person release]; //没有retain,不必release
    6     [superdealloc];
    7 }
    8 
    9 @end
     
    D.autorelease方法
    不使用ARC且在开启Enable Zombie Objects的时候,使用retainCount=0的对象指针会发生运行时错误
     1  
     2     Person*p =nil;
     3    
     4    //创建自动释放池
     5    @autoreleasepool
     6     {//自动释放池开始
     7        // autorelease方法会返回对象本身
     8        // autorelease会将对象放到一个自动释放池
     9        //当自动释放池被销毁的时候,会对池子里面的所有对象做一次release操作
    10         p = [[[Personalloc]init]autorelease];
    11        
    12         p.age=10;
    13 
    14     }//自动释放池销毁,所有对象release一次
    15    
    16 //    p.age = 20; //运行时错误
     
    @autoreleasepool可以嵌套使用
     
    错误用法:
    (1)alloc之后调用autorelease,又调用release
    (2)多次调用autorelease
     
     
    E.autorelease的实际应用
    1.自定义包装了autorelease的构造、初始化方法
    1 + (id) person
    2 {
    3    return[[[Personalloc]init]autorelease];
    4 }
     
    2.子类调用父类的这种包装方法的时候,返回的对象是父类对象,不符合需求
    解决:
    方式1:重写方法
    方式2:创建对象的时候不使用类名,使用self进行alloc、init
    1 + (id) person
    2 {
    3    return[[[selfalloc]init]autorelease];
    4 }
     
     
     
  • 相关阅读:
    Python基础总结之初步认识---class类(上)。第十四天开始(新手可相互督促)
    Python基础总结之认识lambda函数、map函数、filter() 函数。第十三天开始(新手可相互督促)
    Python基础总结之异常、调试代码第十二天开始(新手可相互督促)
    Python基础总结之再看函数第十一天开始(新手可相互督促)
    Python基础总结之第十天开始【认识模块、包和库】(新手可相互督促)
    Python基础总结之第十天开始【认识一下python的另一个数据对象-----字典】(新手可相互督促)
    Python基础总结之第九天开始【python之OS模块对目录的操作、以及操作文件】(新手可相互督促)
    Python基础总结之第八天开始【while循环以及for循环,循环嵌套等循环相关的知识点】(新手可相互督促)
    Python基础总结之第七天开始【总结字符串、列表、元组的常用方法】(新手可相互督促)
    个人 Golang 编程规范
  • 原文地址:https://www.cnblogs.com/hellovoidworld/p/4119377.html
Copyright © 2020-2023  润新知