zoukankan      html  css  js  c++  java
  • [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 }
    如果一件事情你觉得难的完不成,你可以把它分为若干步,并不断寻找合适的方法。最后你发现你会是个超人。不要给自己找麻烦,但遇到麻烦绝不怕,更不要退缩。 电工查找电路不通点的最快方法是:分段诊断排除,快速定位。你有什么启示吗? 求知若饥,虚心若愚。 当你对一个事情掌控不足的时候,你需要做的就是“梳理”,并制定相应的规章制度,并使资源各司其职。
  • 相关阅读:
    F2E Tool(前端工程师的工具箱)
    SQLServer 语句存档整理
    MySQL DATE_FORMAT() 函数
    sqlserver 自连接 生成一列数据
    mysql存储引擎:InnoDB和MyISAM的差别/优劣评价/评测/性能测试
    好书推荐
    Flashfxp 3.4的注册码
    mysql事务处理
    mysql 时间函数 格式化
    【转】PowerDesigner 中将Comment(注释)及Name(名称)内容互相COPY的VBS代码
  • 原文地址:https://www.cnblogs.com/wvqusrtg/p/4501623.html
Copyright © 2011-2022 走看看