• Objective-C汇总


    Objective  C(20世纪80年代初)
    一、OC语言概述
        1.1985年,Steve  Jobs成立了NeXT公司
        2.1996年,12月20日,苹果公司宣布收购了NeXT  software 公  司,NEXTSTEP环境为apple公司下主要开发、发行操作 系统OSX的基础,这个开发环境的版本被苹果公司命名为 Cocoa(可可)框架    
             NSString  NS=NEXTSTEP
       3.Cocoa框架  (Cocoa  Touch框架  ->Ctapp ) 
            1.Fundation框架,基础框架,包括:字符串、数字、数组、 字典、集合等  
                      框架名称          头文件
    #import  <Foundation/Foundation.h>  
             2.Application  Kit框架,应用程序工具箱,它包括了实现程 序图形、事件驱动和用户界面的全部对象,窗口、对话框、按 钮、菜单、滚动条、文本框等,而且这个列表还在不断的添加 
     二、OC与C区别
        1.创建项目的时候,type—>Foundation(OC)
        2.main.c->main.m(源代码)
        3.#include <stdio.h> -> #import <Foundation/Foundation.h>
        4.在OC的开发环境中,是兼容C的语法
        5.printf()—>NSLog(@….);日志输出
         6. 编译原理OC与C是一样的,只不过编译命令由原来的gcc->clang。eg:clang -framework Foundation main.m
    三、逻辑数据类型BOOL  
    OC中的逻辑值类型: 
       1.BOOL  b2  =  YES;//*YES  1  NO  0
        2.不用导入头文件
            //C中的逻辑值类型
            bool isBool = false;
            //***OC中的逻辑值类型
            BOOL isBool2 = YES;
            if (isBool2) {
                NSLog(@"条件成立!");
            }else{
                NSLog(@"条件不成立!");
            }
    结果:条件成立!
    三、OC中的函数
    练习:求两个数的关系  a是否大于b
                     1.函数实现    返回值(逻辑类型值)
                      2.在main函数中传入两个值并得到结果
                      3.通过if与结果判断,输出结果(NSLog)
    #import <Foundation/Foundation.h>
    
    BOOL bu(int i,int j){
        if (i>j) {
            return YES;
        }
        else{
            return NO;
        }
    }
    
    int main(int argc, const char * argv[])
    {
        @autoreleasepool {
            int a=5,b=6;
            BOOL isFlag=bu(a,b);
            if (isFlag) {
                NSLog(@"%d>%d",a,b);
            }
            else{
                NSLog(@"%d<%d",a,b);
            }
        
        }
        return 0;
    }
    结果:5<6
    四、什么是面向对象程序开发   
    1.面向过程  
         数据结构  +  算法  
     2.面向对象       
          属性  +  行为   
    计算机中的对象Student: (有什么+能干什么) 
       属性(成员)  age,name  
       方法(函数)study()  
    如:现实中周边一个对象      ->    计算机中对象?
                     学生                                  Student
            有什么: 姓名、年龄             属性:name、age
            能什么: 学习                         方法:study()
    五、类与对象(抽象事物,内存中不存在)
      1.类是对象还未产生时,将要是什么样,具有相同属性和行为方法的同一类元素的总称
       2.对象就是类经过实例化所产生的一个内存趋于数据
    *必须先有类经过实例化才会产生对象,程序需要的是具体的数据,所以程序在执行过程当中,需要的对象。
    3.第一个面向对象程序:
         1. 类(文件中的代码)
               在计算机中每一个类被存在两个文件中:
                一、.h声明….属性/方法(属性没有实现,只有声明)
                         @interface  Student  :  NSObject   //类名Student
                      @property  int  age;//声明属性  
                       -(void)study;//声明方法  @end  
                  二、 .m实现....方法
                           @implementation  Student   //方法的定义、实现  
                        -(void)study{  
                                 NSLog(@"学生执行了study方法");   }  
                        @end 
             2.实例化(main.m文件 )
              类—>对象
           在需要使用对象的地方实例化
                 1.导入头文件
                       #import "Student.h"
          2.对一个类进行实例化
                           [类 alloc] 实例化得到一个内存(堆)的首地址
                        [Student alloc]
              通过类发送alloc,通过一个类创建对象,通过stu变量,找 到内存的对象
             //给类Student 发消息alloc会创建出一个Student类型的对象
          3.Student* stu=[Student alloc]实例化;stu就是对象
     3.操作对象
         属性:给属性赋值或取属性的值
                      对象.属性=......;//赋值
                      …=对象.属性;//取值
                方法:
                      [对象 方法名]调用对象的方法
    ***完整程序
    Student.h声明
    #import <Foundation/Foundation.h>
    //声明
    @interface Student : NSObject //父类
    //属性
    @property int age;
    //方法
    -(void)study;
    @end
    
    Student.m实现
    #import "Student.h"
    
    @implementation Student
    -(void)study{
        NSLog(@"学生有学习的能力!");
    }
    @end
    
    main.m
    #import <Foundation/Foundation.h>
    #import "Student.h"
    
    int main(int argc, const char * argv[])
    {
        @autoreleasepool {
            
            // [类 alloc] 实例化得到一个内存(堆)的首地址
            //返回void*-->id任意类型指针
            //指针变量 地址-->对象(obj)
            //id obj=[Student alloc];
            //Student* stu=(Student*)obj;
            
            //stu *对象 指针 实例 引用
            Student* stu=[Student alloc];
            
            //操作对象
            stu.age=18;//属性赋值
            [stu study];//调用对象的方法   //发送一个消息
            NSLog(@"age:%d",stu.age);//得到属性值
            
        }
        return 0;
    }
    结果:
    学生有学习的能力!
    age:18
    
    知识点
    一、方法(实质是函数)
    
    • 什么是方法 (method) 
    代表一个对象可以干什么,一般来讲方法必须与对象结合使用
对象中内容分为属性和方法两部分 : 
   - 属性是对象中的数据成员,用于描述对象的特征  
       - 方法是对象中的函数成员,用于描述对象的行为
    3.关于函数
    
       1. C语言的函数     返回类型  函数名();
    
        2.Oc中函数的一般格式:
    
        类型标识  (返回值类型) 函数名:(参数类型)参数名;
            +/-        (void)             show;       int
    语法格式:
          1.-(返回值类型)方法名; //无参方法
                //无返回值 无参数的方法 method
             -(void)method;
    
        2.-(返回值类型)方法名:(参数类型)参数名;//有一个参数方法
                 //有一个参数的方法
          //返回值类型 方法名:(参数的类型)参数名;
          -(void)method2:(int)arg;
    
        3.-(返回值类型)方法名:(参数类型1)参数名1 :(参数类型2)参数名2;//有两个参数的方法
                   
        -(void)method3:(int)age :(char)sex //需注意参数名后需加空格再加冒号
                         
        4.-(返回值类型)方法名:(参数类型1)参数名1 :(参数类型2)参数名2 :(参数类型n)参数名n;//3…n…个参数
           //返回值类型 方法名:(参数的类型)参数名 :(参数的类型)参数名 ...n;
           /*定义一个方法,传多个参数:
           参数1年龄、参数2性别、参数3学号
           参数4工资、参数5家里有几个人。*/
        (1)   -(void)method3:(int)age
                            :(char)sex //需注意参数名后需加空格再加冒号
                            :(int)num  
                            :(float)salary 
                            :(int)count;
             (2)     -(void)method4WithAge:(int)age
                             andSex:(char)sex
                             andNum:(int)num
                          andSalary:(float)salary 
                           andCount:(int)count;
    
    练习:/*定义一个方法,传多个参数:类:MyClass
           参数1年龄、参数2性别、参数3学号
           参数4工资、参数5家里有几个人。*/
    MyClass.h
    #import <Foundation/Foundation.h>
    
    @interface MyClass : NSObject
    
    -(void)method4WithAge:(int)age
                   andSex:(char)sex
                   andNum:(int)num
                andSalary:(float)salary andCount:(int)count;
    
    @end
    MyClass.m
    #import "MyClass.h"
    
    @implementation MyClass
    -(void)method4WithAge:(int)age
                   andSex:(char)sex
                   andNum:(int)num
                andSalary:(float)salary andCount:(int)count{
         NSLog(@"age:%d sex:%c num:%d salary:%f count:%d",age,sex,num,salary,count);
    }
    @end
    Main.m
    #import <Foundation/Foundation.h>
    
    #import "MyClass.h"
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            //将类实例化变为对象
            MyClass *myClass = [MyClass alloc];
            
            [myClass method4WithAge:19 andSex:'M' andNum:1 andSalary:2000.0f andCount:4];
                }
        return 0;
    }
    结果:
    age:19 sex:M num:1 salary:2000.000000 count:4
    
    2.公有方法、私有方法
         1. 公有方法:即在.h文件中声明,又在.m文件实现。
            可以在任意文件中使用。[对象 method];
        2.私有方法:没在.h文件中声明,但在.m文件实现。
            只可以在当前(同一)文件中使用,即在main.m文件中不能使用。通过[self method]实现;
          3.self
                 self代表对象自己
               self.属性  调用对象自己的属性值
              [self 方法] 调用对象自己的方法
    例:
    MyClass.h
    #import <Foundation/Foundation.h>
    
    @interface MyClass : NSObject
    -(void)publicMethod;//公有方法
    @end
    
    MyClass.m
    -(void)publicMethod{
        NSLog(@"公有方法执行了");
       [self privateMethod];//可以实现私有方法
    }
    -(void)privateMethod{
        NSLog(@"私有方法执行了");
    }
    @end
    Main.m
    [myClass publicMethod];//公有方
    //[myClass privateMethod];//不能调用类的私有方法  不执行报错
    结果:
    公有方法执行了
    私有方法执行了
    
    3.成员变量、实例变量
    变量就是保存一个数据。
        1.成员变量将要保存什么数据。(_变量名)
                    @interface MyClass : NSObject
    
                { int _i;}//成员变量    //必须用大括号括起来      不能初始化
    
        2.实例变量真正保存什么数据。
        3.公有的实例变量与私有的实例变量,最大的区别就是在对象外可见和不可见。默认情况,都不可以直接进行操作。
        4.如果需要操作一个实例变量,目前的操作方式只有方法,通过方法来操作实例变量。(方法是操作实例变量的一种方式)。
    如:
    Point2.h
    #import <Foundation/Foundation.h>
    
    @interface Point2 : NSObject
    {
        int i;//定义成员变量
    }
    
    -(void)seti1:(int)num;//赋值
    -(int)geti1;//取值 返回值
    @end
    Point2.m
    #import "Point2.h"
    
    @implementation Point2
    -(void)seti1:(int)num{
        i=num;//把参数赋给成员变量,转成用方法进行内部操作
    }
    -(int)geti1{
        return i;//将成员变量值返回
    }
    @end
    main.m
    #import <Foundation/Foundation.h>
    #import "Point2.h"
    
    int main(int argc, const char * argv[])
    {
        @autoreleasepool {
           
            Point2* stu=[Point2 alloc];
            [stu seti1:18];//给实例变量赋值
            NSLog(@"i:%d",[stu geti1]);//得到实例变量的值
            
            
        }
        return 0;
    }
    结果:
    i:18
    
    知识点
    二、属性
    
        是访问实例变量的一种方式。
    
         1.变量的访问修饰符
              • 定义变量  
            –  @public (公有) 可以在任意位置访问   
            –  @package  可以在包内部访问,一个项目一定是在同一个 包下。   
            –  @protected (受保护) 可以在本类内部和子类内部访问   
            –  @private(私有)  只可以在本类的内部分访问   
            *以上在@implementation部分,用大括号括起来   
            –  默认访问权限:@protected   
    如:
    Myclass.h
    #import <Foundation/Foundation.h>
    
    @interface Myclass : NSObject
    {
        int _i;//实例变量    默认protected
        @package int _i2;
        @public  int _i3;
        @protected int _i4;
        @private int _i5;
    }
    
    @end
    main.m
    #import <Foundation/Foundation.h>
    #import "Myclass.h"
    
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            Myclass* myclass=[Myclass alloc];
            myclass->_i2=20;//package 这个项目里使用
            myclass->_i3=30;//public  其他的不能访问
        }
        return 0;
    }
    
    2.属性
         1.属性是访问实际变量的一种方式
         2.属性有两个方法组成(setter/getter方法)。(属性是方法)
         3.属性本身不能保存数据,数据是由实例变量保存的
    
    
    规范: 实例变量的命名:_开头
                 实例变量对应的属性:去掉下划线,首子母大写
               如果认为规范不满意,自己重新合成
    
     一、属性的本质三部分组成
           a.实例变量
                  int  _age
           b.setter和getter方法的声明与实现    
                1.)setter方法:方法名:“set”+属性名并首子母大写 +“:”+和属性类型一样的参数,无返回值。 
                        -(void)setSex:(char)sex  //_age去掉下划线首子母大写2.)getter方法:方法名和属性名一样,没有参数,返回值类型 和属性类型一样。
                            -(char)sex;
       c.点语法
              setter方法的实现主要用来给属性赋值的  
           getter方法的实现主要用来读取属性值的  
                 对象.属性  =  值;=>会自动调用setter方法  
                 变量  =  引用.属性;=>会自动调用getter方法
                   myclass.sex='m';//自动调用setter方法
             myclass.age=18;
            NSLog(@"sex:%c age%d",myclass.sex,myclass.age);
    
    练习:对象有性别、年龄的属性
    完整程序:
    
    Myclass.h
    #import <Foundation/Foundation.h>
    
    @interface Myclass : NSObject
    {
        char _sex;//实例变量
        int _age;
    }
    -(void)setSex:(char)sex;
    -(char)sex;
    
    -(void)setAge:(int)age;
    -(int)age;
    
    @end
    Myclass.m
    #import "Myclass.h"
    
    @implementation Myclass
    -(void)setSex:(char)sex{
        _sex=sex;//赋值 属性与实例变量的关联
    }
    -(char)sex{
        return _sex;//取值 属性与实例变量的关联
    }
    
    -(void)setAge:(int)age{
        _age=age;
    }
    -(int)age{
        return _age;
    }
    @end
    main.m
    #import <Foundation/Foundation.h>
    #import "Myclass.h"
    
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            
            Myclass* myclass=[Myclass alloc];
            //实例变量->(return/=)->setter/getter
            //setter/getter(语法)<->属性名
            //实例变量<->属性名
            myclass.sex='m';//自动调用setter方法 [myclass setSex:’m’]
            myclass.age=18;
            NSLog(@"sex:%c age:%d",myclass.sex,myclass.age);//自动调用getter方法
        }
        return 0;
    }
    结果:sex:m age:18
    二 、声明式属性
         a.定义实例变量
         b. @property 属性类型 属性名(自动生成setter/getter)
            @property int age;(.h)
        @synthesize 属性名=实例变量
           @synthesize age=_age;(.m)
         c.点语法
    
    完整程序
    Myclass.h
    #import <Foundation/Foundation.h>
    
    @interface Myclass : NSObject
    {
        int _age;//1.实例变量
    }
    //2.声明属性
    @property int age;//属性
    @property char sex;
    @end
    Myclass.m
    #import "Myclass.h"
    
    @implementation Myclass
    @synthesize age=_age;///将属性与实例变量关联在一起
    @synthesize sex=_sex;
    @end
    main.m
    #import <Foundation/Foundation.h>
    #import "Myclass.h"
    
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            
            Myclass* myclass=[Myclass alloc];
          
            myclass.age=18;
            myclass.sex='f';
            NSLog(@"age:%d sex:%c",myclass.age,myclass.sex);
        }
        return 0;
    }
    结果:age:18 sex:f
    三、ios5中的属性
      
      a.定义实例变量 (省略)
         b. @property 属性类型 属性名(自动生成setter/getter)
            @property int age;(.h)
        @synthesize 属性名=实例变量
           @synthesize age=_age;(.m)
         c.点语法
    四、ios6中的属性
        实例变量都有系统生成的,就不需要合成
        a.定义实例变量 (省略)
          **b. @property 属性类型 属性名(自动生成setter/getter)
            @property int age;(.h)
        @synthesize 属性名=实例变量(省略)
           @synthesize age=_age;(.m)
             c.点语法
    
    注:如果对系统生成的setter/getter方法不满意,是可以重写这两个方法(必须两个方法都重写)。(声明属性/setter/getter),但是必须写合成。
          在setter/getter方法中,使用点语法要注意(死循环)不要用self.属性名
      如:
    Myclass.h
    #import <Foundation/Foundation.h>
    
    @interface Myclass : NSObject
    
    @property int age;//属性
    @property char sex;
    @end
    Myclass.m
    #import "Myclass.h"
    
    @implementation Myclass
    
    @synthesize age=_age;///将属性与实例变量关联在一起     必须合成
    -(void)setAge:(int)age{
        _age=age+5;             //同时调用setter和getter方法,给属性手动+5
    }
    -(int)age{
        return _age;
    }
    
    @end
    main.m
    #import <Foundation/Foundation.h>
    #import "Myclass.h"
    
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            
            Myclass* myclass=[Myclass alloc];
          
            myclass.age=18;
            myclass.sex='f';
            NSLog(@"age:%d sex:%c",myclass.age,myclass.sex);
        }
        return 0;
    }
    结果:age:23 sex:f
    知识点
    三、初始化
    
    //在创建的时候,就可以确定对象的值,使用初始化方法更简单、直接
    //当程序在执行过程当中,如果需要给属性赋值,就使用方法和*属性
    
        *真正初始化对象是由父类解决的
                     self=[super init]//哪个对象执行的初始化操作,将结果给哪个对象本身(自己)
           return self;//当初始化操作完毕之后,经结果返回。
    
         1.初始化(默认值)对象。(无参的初始化方法)
             即使不定义无参的初始方法,对象本身也具备。
           如果对原有的初始化方法不满意,是可以自定义的
         2.初始化(指定值)对象。(有参的初始化方法)
              有参的初始化方法必须自定义。
                1.有参的都以“initWith...”开头(规定)
                    2.初始化方法只能用一次
    int i ;
    int i = 0;//默认值
    int i = 10;//指定值
    
    [MyClass alloc];
    [MyClass alloc]init];//默认值 无参的初始化方法
    [MyClass alloc]initWithAge:18];//指定值 有参的初始化方法
    
    完整有参初始化方法程序:
    Student.h
    #import <Foundation/Foundation.h>
    
    @interface Student : NSObject
    @property int age;//属性
    @property char sex;
    @property int num;
    
    -(id)initWithAge:(int)age andSex:(char)sex andNum:(int)num;//有参初始化
    
    @end
    
    Student.m
    #import "Student.h"
    
    @implementation Student
    
    -(id)initWithAge:(int)age andSex:(char)sex andNum:(int)num{
        self=[super init];
        if (self) {
            //默认初始化成功后,初始化其他属性值
            _age=age;  参数赋给属性
            //self.sex=sex;//同等
            _sex=sex;
            _num=num;
        }
        return self;
    }
    
    @end
    
    main.m
    #import <Foundation/Foundation.h>
    #import "Student.h"
    
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            //Student* student=[[Student alloc]init];
            
            Student* student=[[Student alloc]initWithAge:18 andSex:'m' andNum:123];
            NSLog(@"age:%d sex:%c num:%d",student.age,student.sex,student.num);
            
        }
        
        return 0;
    }
    结果: age:18 sex:m num:123
    *创建类的时候,加前缀,前缀大写,类名大写,加起来不超过4个
     注意区分不同的知识点:实例变量_age    参数age     属性.age
    2.id类型   任意类型指针
    id是一个指针,但在使用时无需加*,相当于void*
    3.self关键字
    代表当前对象本身,还可以代表当前类
    1.[myclass method];
      如果method方法中,有一个self关键字,self就相当于myclass对象本身。
    2.在对象的内部如果调用本身的属性,self.属性
                               如果调用本身的属性,[self 方法]
    4.super关键字
    
    练习:
    创建两个Point2对象,它有横坐标x,纵坐标y。
        保存两个坐标值。
        (1)普通方法set/get方法 普通方法
    TRPoint.h
    #import <Foundation/Foundation.h>
    
    @interface TRPoint : NSObject
    {
        //实例变量
        int _x;//横坐标
        int _y;//纵坐标
    }
    //普通方法
    -(void)setX:(int)x;//赋值
    -(int)getX;//取值
    -(void)setY:(int)y;//赋值
    -(int)getY;//取值
    -(void)show;//查看横、纵坐标
    @end
    
    TRPoint.m
    #import "TRPoint.h"
    
    @implementation TRPoint
    -(void)show{
        //普通方法也可以访问实例变量
        NSLog(@"横坐标:%d 纵坐标:%d",_x,_y);
        //NSLog(@"横坐标:%d 纵坐标:%d",[self getX],[self getY]);
    }//查看横、纵坐标
    -(void)setX:(int)x{
        _x = x;
    }//赋值
    -(int)getX{
        return _x;
    }//取值
    -(void)setY:(int)y{
        _y = y;
    }//赋值
    -(int)getY{
        return _y;
    }//取值
    @end
    
    main.m
    TRPoint *p1 =[TRPoint alloc];
            [p1 setX:3];//普通方法赋值
            [p1 setY:4];
            [p1 show];
    结果:横坐标:3 纵坐标:4
        (2)属性
            <1>属性本质
            <2>声明式属性
            <3>ios5
            <4>ios6
    
    **show取值:
    -(void)show{
        1.//普通方法中可以直接访问实例变量
        //NSLog(@"横坐标:%d 纵坐标:%d",_x,_y);
        2.//getter方法也可以访问实例变量
        //NSLog(@"横坐标:%d 纵坐标:%d",[self x],[self y]);
        3.//属性可以访问实例变量
        NSLog(@"横坐标:%d 纵坐标:%d",self.x,self.y);
    }
    
        (3)初始化方法
    
    知识点
    四、实例方法、类方法
    1.方法分为两类:
          1.实例方法
                -开头的方法,都是实例方法;
                通过实例调用的方法
         [myClass method];
           2.类方法
                +开头的方法,都是类方法;
                 通过类调用的方法是类方法
                  [TRMyClass method2];
    2.实例方法
     -实例方法就是对象方法
     -实例方法必须在定义对象之后,由对象来调用
    3.类方法
    -类方法就是静态方法  (代码区)
    -类方法主要的使用就是用来创建对象的
    - 类方法不能访问实例变量和属性,但类方法可以创建对象,通过对象访问实例变量和其属性
     ***类方法与实例方法区别         
    - 实例方法与实例有关系的,所以实例方法可以调用、读取实 例中的实例变量或属性。  
    - 类方法与实例无关系的,所以类方法不可以调用、读取实例 例中实例变量和属性。  
    - 在类方法中可以创建对象,当然访问该对象的实例变量和属 性。  
    
    4.工厂方法
    类方法用来创建对象的方法就是工厂方法
        1.无参工厂方法
                创建对象,并给属性一个默认值。
     +(TRStudent*)student{
        return [[TRStudent alloc]init];
    }
        2.有参工厂方法
                1.要依赖有参的初始化方法
                    -(id)initWithAge:(int)age;
                2.创建对象,并给属性一个指定的值
    +(TRStudent*)studentWithAge:(int)age andSex:(char)sex andSalary:(double)salary{   //TRStudent*类型
       return  [[TRStudent alloc]initWithAge:age andSex:sex andSalary:salary];
    }
    规范:
    工厂方法的方法名一定以类名开头,注意去除了前缀,首字母 要小写
    工厂方法,不但使用自定义类,官方的类也遵守这个规范
    
    练习:重构5个对象 的年龄、性别、工资  工厂方法
    完整程序:
    TRStudent.h
    #import <Foundation/Foundation.h>
    
    @interface TRStudent : NSObject
    @property int age;
    @property char sex;
    @property double salary;
    
    //方法
    -(void)show;
    
    //有参初始化
    -(id)initWithAge:(int)age andSex:(char)sex andSalary:(double)salary;
    
    //无参的工厂方法
    +(TRStudent*)student;
    
    //有参工厂方法
    +(TRStudent*)studentWithAge:(int)age andSex:(char)sex andSalary:(double)salary;
    
    @end
    
    TRStudent.m
    #import "TRStudent.h"
    
    @implementation TRStudent
    
    //方法查看
    -(void)show{
        NSLog(@"age:%d sex:%c salary:%f",_age,_sex,_salary);
    }
    
    //有参初始化实现
    -(id)initWithAge:(int)age andSex:(char)sex andSalary:(double)salary{
        self=[super init];
        if (self) {
            _age=age;
            _sex=sex;
            _salary=salary;
        }
        return self;
        
    }
    
    //无参工厂方法实现
    +(TRStudent*)student{
        return [[TRStudent alloc]init];
    }
    
    //有参工厂方法实现
    +(TRStudent*)studentWithAge:(int)age andSex:(char)sex andSalary:(double)salary{
       return  [[TRStudent alloc]initWithAge:age andSex:sex andSalary:salary];
    }
    @end
    
    main.m
    #import <Foundation/Foundation.h>
    #import "TRStudent.h"
    
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            //初始化方法使用
          TRStudent* stu=[[TRStudent alloc]initWithAge:20 andSex:'F' andSalary:5600];
               [stu show];
         TRStudent* stu2=[TRStudent studentWithAge:18 andSex:'M' andSalary:5000];
            [stu2 show];
            
          //工厂方法使用
           TRStudent* stu3=[TRStudent studentWithAge:19 andSex:'F' andSalary:5500];
           [stu3 show];
            
              }
        return 0;
    }
    结果:
    age:20 sex:F salary:5600.000000
    age:18 sex:M salary:5000.000000
    age:19 sex:F salary:5500.000000
    
    5.单例模式(Singleton)
    *有时候只需要一个对象,并且这个对象是唯一的,单例模式
      利用类方法来创建和访问对象
    
      *注:现在所说的单例不严谨,alloc还可以创建新的对象,要注意只能使用单例模式方法创建对象。
           在多线程里面,会有办法解决alloc永远也只创建一个对象。
    TRStudent.h
    #import <Foundation/Foundation.h>
    
    @interface TRStudent : NSObject
    //类方法
    //返回值类型也是对象类型
    +(TRStudent*)shareStudent;
    
    @end
    TRStudent.m
    #import "TRStudent.h"
    //全局变量
     static TRStudent* stu=nil;
    
    @implementation TRStudent
    
    +(TRStudent*)shareStudent{
        if (stu==nil) {//原来没有创建过对象
            stu=[[TRStudent alloc]init];
        }
        return stu;
    }
    @end
    main.m
    #import <Foundation/Foundation.h>
    #import "TRStudent.h"
    
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            TRStudent*stu1=[TRStudent shareStudent];
             NSLog(@"%p",stu1);
            TRStudent*stu2=[TRStudent shareStudent];
             NSLog(@"%p",stu2);
        }
        return 0;
    }
    结果:
    0x100202ff0
    0x100202ff0
    知识点
    五、MRC内存管理
    
    1.内存管理
     在计算机中,堆内存的使用,是需要程序员手动创建,并且使用完毕
    以后要手动销毁(回收),这个过程叫做内存管理。
    在OC中,内存管理又有两种方式:
            MRC:手动内存管理 完全由程序员控制
            ARC:自动内存管理  由程序员通知编译,编译帮我们控制
    • 进程空间  
- 代码区:只读。  
- 堆:自己创建、自己回收释放,对象是保存在堆区的。 
    - 全局区:进程启动时分配,进行结束时释放。  
- 栈:局部变量,自动创建、自动释放空间
    2.MRC手动内存管理
    注:ios6,强制使用ARC
    
    *改项目内存管理
    1.项目默认的内存管理是ARC,将内存管理改为MRC
    项目—>Basic(选择ALL)—>右搜索(ARC)—>Apple LLVM 5.1-Language -Objective C (Automatic Reference Counting ) —>No
    2.由于程序在执行的时候,不一定立刻回收堆内存,可能会出现异常,也可能不会出现。
        Edit Schema->Run…->Diag…->Mem…Manage…Objective-C Enabel Zombie Objects 打开
    
     MRC手动管理引用计数器
        Manual手动
        Reference Counting引用计数器
    一、程序通过代码通知引用计数器做加1或减1操作:
           1.向对象发送alloc、copy、new通知引用计数器加1.
                  在OC当对象不再使用时候,如果忘记发送release消息,内存溢出,资源浪费
           2.当对象不再使用,发送release通知引用计数器减1.
             3.当引用计数器为0时,会自动释放该对象的堆内存空间
             4.当对象销毁时,会自动执行dealloc方法
           当对象销毁时,对象中的实例变量、方法均不可用,内存管理存在的问题
    二、内存管理存在的问题:
            (1)如果对象销毁,但引用的值还在存,此时存在野指针问题,使用空指针解决野指针问题。
            并且对象的实例方法与实例变量不可使用,否则会报异常、crash。
            (2)如果对象未销毁,此时存在内存泄漏问题,造成资源浪费。
    
    3.release和dealloc    
      1.[stu release];//销毁对象,引用计数器减1,变为0,自动执行dealloc
      2.//当引用计数器为0时,会自动销毁对象
       -(void)dealloc{
        //真正的对象销毁由父类操作的
        [super dealloc];}
    4.retainCount和retain
     1.[stu retainCount]//查看当前计数器的值RC
     2.[stu retain];//通知引用计数器加1
     3.[stu release];//通知引用计数器减1
    //内存管理原则,哪里加1,就去哪里减1
    5.声明式属性
        a.不但解决了内存的赋值问题,还解决了内存问题。
        b.默认情况下,声明式没有解决内存问题。
        @property(retain) TRBook* book;解决内存问题
        c.声明式属性只解决了setter(所有情况)/getter(没有内存问题)内存问题
        注:减1操作,还是需要手动在dealloc方法里面解决
    
    ***总结:
        一个对象的内存管理
        两个引用共用一个对象的内存管理
        一个对象的属性是引用类型的内存管理
        一个对象的属性的引用如果发生改变时的内存管理
        声明式属性的内存管理
    
    一、一个对象的内存管理证明:(空指针和野指针问题)
    TRStudent.h
    #import <Foundation/Foundation.h>
    
    @interface TRStudent : NSObject
    -(void)study;
    @end
    TRStudent.m
    #import "TRStudent.h"
    
    @implementation TRStudent
    -(void)study{
        NSLog(@"学生具有学习的能力");
    }
    //当引用计数器为0时 会自动销毁对象 并自动执行该方法
    -(void)dealloc{
        NSLog(@"dealloc执行销毁stu");
        //真正的对象销毁由父类操作的
        [super dealloc];
    }
    @end
    main.m
    #import <Foundation/Foundation.h>
    #import "TRStudent.h"
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            //RC:1
            TRStudent *stu = [[TRStudent alloc]init];
            
            NSUInteger count = [stu retainCount];//可以查看对象引用计数器的值
            NSLog(@"count:%lu",count);
            [stu study];
            //RC:0
            NSLog(@"release销毁前");
            [stu release];
            //查看对象的引用计数器的值,在对象销毁后是可能有问题的
          /*  count = [stu retainCount];
            NSLog(@"count2:%lu",count); */
            
            //stu引用,相当于代表两个值
            //stu引用指向对象的值(数据)
            //stu引用本身的值(地址)
            //在OC野指针问题也叫crash、异常
            //在OC当对象不再使用时候,如果忘记发送release消息,内存溢出,资源浪费
            stu = nil;//空指针解决野指针问题
            //在OC当中,可以向空引用发送消息 没有任何反应
            NSLog(@"stu:%p",stu);
            [stu study];//野指针
            NSLog(@"release销毁后");
        }
        return 0;
    }
    结果:
    count:1
    学生具有学习的能力
    release销毁前
    dealloc执行销毁stu
    stu:0x0
    release销毁后
    二、两个引用共用一个对象的内存管理
    TRStudent.h
    #import <Foundation/Foundation.h>
    
    @interface TRStudent : NSObject
    -(void)study;
    @end
    TRStudent.m
    #import "TRStudent.h"
    
    @implementation TRStudent
    -(void)study{
        NSLog(@"学生具有学习的能力");
    }
    //当引用计数器为0时 会自动销毁对象 并自动执行该方法
    -(void)dealloc{
        NSLog(@"dealloc销毁");
        //真正的对象销毁由父类操作的
        [super dealloc];
    }
    @end
    main.m
    #import <Foundation/Foundation.h>
    #import "TRStudent.h"
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            //RC:1
            TRStudent *stu = [[TRStudent alloc] init];
            stu和stu2共用一个内存空间
            TRStudent *stu2 = stu;//引用赋值 不会通知引用计数器加1
            [stu2 retain];//通知引用计数器加1 RC:2
            
            NSLog(@"RC:%lu",[stu retainCount]);
            
            [stu study];
            [stu release]; //通知引用计数器减1 //RC:2-1
           
            [stu2 study];
            [stu2 release];//RC:0
            
            
        }
        return 0;
    }
    结果:
    RC:2
    学生具有学习的能力
    学生具有学习的能力
    dealloc销毁
    三、一个对象的属性是引用类型的内存管理证明
    TRBook.h
    #import <Foundation/Foundation.h>
    
    @interface TRBook : NSObject
    @property int price;
    @end
    TRBook.m
    #import "TRBook.h"
    
    @implementation TRBook
    -(void)dealloc{
        NSLog(@"TRBook销毁了");
        [super dealloc];
    }
    @end
    TRStudent.h
    #import <Foundation/Foundation.h>
    #import "TRBook.h"
    @interface TRStudent : NSObject
    {
        TRBook* _book;
    }
    //setter/getter
    -(void)setBook:(TRBook*)book;
    -(TRBook*)book;
    -(void)study;
    @end
    TRStudent.m
    #import "TRStudent.h"
    
    @implementation TRStudent
    -(void)setBook:(TRBook*)book{
        _book = book;
        [_book retain];
    }
    -(TRBook*)book{
        return _book;
    }
    -(void)study{
        NSLog(@"学生具有学习的能力 看书:%d",self.book.price);
    }
    //当引用计数器为0时 会自动销毁对象 并自动执行该方法
    -(void)dealloc{
        [_book release];
        NSLog(@"TRStudent销毁了");
        //真正的对象销毁由父类操作的
        [super dealloc];
    }
    @end
    main.m
    #import <Foundation/Foundation.h>
    #import "TRStudent.h"
    #import "TRBook.h"
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            TRBook *sanguo = [[TRBook alloc]init];
            sanguo.price = 10;
            TRStudent *stu = [[TRStudent alloc]init];
            stu.book = sanguo;
            [sanguo release];
            [stu study];
            [stu release];
            //内存管理原则:哪里加1,哪里就有责任减1
        }
        return 0;
    }
    结果:
    学生具有学习的能力 看书:10
    TRBook销毁了
    TRStudent销毁了
    四、一个对象的属性的引用如果发生改变时的内存管理
    TRBook.h
    TRBook.m
    同上
    TRStudent.h
    同上
    TRStudent.m
    #import "TRStudent.h"
    
    @implementation TRStudent
    -(void)setBook:(TRBook*)book{
        if (_book==nil) {
            _book = book;
            [_book retain];
        }else{
            [_book release];
            _book = book;
            [_book retain];
        }
    }
    -(TRBook*)book{
        return _book;
    }
    -(void)study{
        NSLog(@"学生具有学习的能力 看书:%d",self.book.price);
    }
    //当引用计数器为0时 会自动销毁对象 并自动执行该方法
    -(void)dealloc{
        [_book release];//三1 水1 学0
        NSLog(@"TRStudent销毁了");
        //真正的对象销毁由父类操作的
        [super dealloc];
    }
    @end
    main.m
    #import <Foundation/Foundation.h>
    #import "TRStudent.h"
    #import "TRBook.h"
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            TRBook *sanguo = [[TRBook alloc]init];
            sanguo.price = 10;
            //三1 水0 学0
            TRBook *shuihu = [[TRBook alloc]init];
            //三1 水1 学0
            shuihu.price = 20;
            TRStudent *stu = [[TRStudent alloc]init];
            //三1 水1 学1
            stu.book = sanguo;[sanguo release];//三1 水1 学1
            [stu study];
            stu.book = shuihu;
            [stu study];//三1 水2 学1
            [stu release];//三1 水2 学0
            [shuihu release];//三1 水0 学0
            //内存管理原则:哪里加1,哪里就有责任减1
        }
        return 0;
    }
    结果:
    学生具有学习的能力 看书:10
    TRBook销毁了
    学生具有学习的能力 看书:20
    TRStudent销毁了
    TRBook销毁了
    
    五、声明式属性的内存管理
    TRBook.h
    TRBook.m
    同上
    TRStudent.h
    #import <Foundation/Foundation.h>
    #import "TRBook.h"
    @interface TRStudent : NSObject
    {
        //TRBook* _book;
    }
    @property(retain) TRBook* book;
    //setter/getter
    /*
    -(void)setBook:(TRBook*)book;
    -(TRBook*)book;
     */
    -(void)study;
    @end
    TRStudent.m
    #import "TRStudent.h"
    @implementation TRStudent
    -(void)study{
        NSLog(@"学生具有学习的能力 看书:%d",self.book.price);
    }
    //当引用计数器为0时 会自动销毁对象 并自动执行该方法
    -(void)dealloc{
        [_book release];//三1 水1 学0
        NSLog(@"TRStudent销毁了");
        //真正的对象销毁由父类操作的
        [super dealloc];
    }
    @end
    
    main.m
    同上
    
    6.自动释放池(autorelease)
    1.可以通过自动释放池管理多个对象的release操作(仅一次)
    2.当自动释放池结束的时候,会向池中每个对象发送release消息
    3.注意两个问题:
          a.一定要有代码块
                @autoreleasepool{}
          b.一定要手动将对象放入自动释放池中
               [对象  autorelease ]
    4.使用场景:
            getter方法需要
            工厂方法需要
            代码使用场景复杂,也会需要
    完整程序:
    TRStufent.h
    #import <Foundation/Foundation.h>
    
    @interface TRStufent : NSObject
    
    @end
    TRStufent.m
    #import "TRStufent.h"
    
    @implementation TRStufent
    -(void)dealloc{
        NSLog(@"对象销毁");
        [super dealloc];
    }
    
    @end
    main.m
    #import <Foundation/Foundation.h>
    #import "TRStufent.h"
    
    int main(int argc, const char * argv[])
    {
        //自动释放池
        @autoreleasepool {//开始
            //默认情况,对象是没有放入自动释放池
            //需要向对象发送autorelease消息,才会将对象放入自动释放池管理
            TRStufent* stu=[[[TRStufent alloc]init]autorelease];
            TRStufent* stu2=[[[TRStufent alloc]init]autorelease];
          NSLog(@"自动释放池末尾");
            
        }
        NSLog(@"程序末尾");
        return 0;
    }
    结果:
    自动释放池末尾
     对象销毁
     对象销毁
      程序末尾
    练习:
    学生和书的故事,可否属性的本质(setter/getter)来解决。工厂方法
    
    7.retain,  assgin, copy, readonly,atomic,nonatomic关键字
          声明式属性的使用:
          声明式属性叫编译期语法
       @property(retain,nonatomic)TRBook*book;
         参数1:
                        retain:修饰引用(对象)数据类型
                     assgin:修饰基本数据类型(默认)
                     copy:一些对象需要复制才能使用NSString
                     readonly:只读,只有setter方法,没有getter方法
              参数2:
                     保证多线程的安全性
                     atomic:原子性 线程是安全的,但效率低(默认)
                     nonatomic: 非原子性 线程是不安全的,但效率高
    练习:
    有一个电脑TRComputer类,能干什么playGame, 显示cpu信息、mem信息。TRCpu类,有运行频率hz x G, TRMem类,有内存的容量size x G。
    1.创建类、对象 
    第一次玩游戏 CS         intelP3 1G hz KingMax 2G size 
    第二次玩游戏 战地4    IntelP4 2G hz KingMax2 8G size
     2.给类添加属性、初始化方法、工厂⽅法
     3.声明式属性⽅方式,解决内存问题。
    完整程序:
    TRCpu.h
    #import <Foundation/Foundation.h>
    
    @interface TRCpu : NSObject
    @property(nonatomic,assign) float hz;
    -(id)initWithHz:(int)hz;
    +(TRCpu*)cpuWithHz:(int)hz;
    @end
    TRCpu.m
    #import "TRCpu.h"
    
    @implementation TRCpu
    -(id)initWithHz:(int)hz{
        self = [super init];
        if (self) {
            self.hz = hz;
        }
        return self;
    }
    +(TRCpu*)cpuWithHz:(int)hz{
        return [[[TRCpu alloc]initWithHz:hz] autorelease];
    }
    -(void)dealloc{
        NSLog(@"cpu销毁了hz:%f",self.hz);
        [super dealloc];
    }
    @end
    
    TRMem.h
    TRMem.m
    同上
    TRComputer.h
    #import <Foundation/Foundation.h>
    #import "TRCpu.h"
    #import "TRMem.h"
    @interface TRComputer : NSObject
    @property(nonatomic,retain)TRCpu *cpu;
    @property(nonatomic,retain)TRMem *mem;
    -(id)initWithCpu:(TRCpu*)cpu andMem:(TRMem*)mem;
    +(TRComputer*)computerWithCpu:(TRCpu*)cpu andMem:(TRMem*)mem;
    -(void)playGame;
    @end
    TRComputer.m
    #import "TRComputer.h"
    
    @implementation TRComputer
    -(id)initWithCpu:(TRCpu*)cpu andMem:(TRMem*)mem{
        self = [super init];
        if (self) {
            //_cpu = cpu;[_cpu retain];
            self.cpu = cpu;
            self.mem = mem;
        }
        return self;
    }
    +(TRComputer*)computerWithCpu:(TRCpu*)cpu andMem:(TRMem*)mem{
        return [[[TRComputer alloc]initWithCpu:cpu andMem:mem] autorelease];
    }
    -(void)playGame{
        NSLog(@"cpu hz:%f mem size:%f",self.cpu.hz,self.mem.size);
    }
    -(void)dealloc{
        [self.cpu release];
        [self.mem release];
        NSLog(@"computer对象销毁了");
        [super dealloc];
    }
    @end
    main.m
    #import <Foundation/Foundation.h>
    #import "TRComputer.h"
    #import "TRCpu.h"
    #import "TRMem.h"
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            TRCpu *intelP3 = [TRCpu cpuWithHz:1];
            TRMem *kingMax = [TRMem memWithSize:2];
            TRComputer *computer = [TRComputer computerWithCpu:intelP3 andMem:kingMax];
            [computer playGame];
            TRCpu *intelP4 = [[[TRCpu alloc]initWithHz:2] autorelease];
            TRMem *kingMax2 = [[[TRMem alloc]initWithSize:8]autorelease];
            computer.cpu = intelP4;
            computer.mem = kingMax2;
            [computer playGame];
            
    
        }
        return 0;
    }
    结果:
    cpu hz:1.000000 mem size:2.000000
    cpu hz:2.000000 mem size:8.000000
    cpu销毁了hz:2.000000
    mem size:8.000000 销毁了
    computer对象销毁了
    mem size:2.000000 销毁了
    cpu销毁了hz:1.000000
    
    知识点
    六、面向对象的三大特性及封装
    1.封装
        1.将信息(属性、方法)封装在一个对象中,
             只给外界公开访问的接口, 而且把具体实现隐藏起来  
    需要公开的内容在.h文件中声明,不需要公开的内容在.m文件中实现(隐藏源代码)
        2.好处:增强可读性、可维护性、可扩展性
         1)代码结构更清晰  
        2)可以和第三方合作,但又保护了源代码,避免泄漏
    2.继承
      1.继承是一种代码复用技术,是类与类之间的一种关系(与内存关)。  
      2.A类继承B类,A类中就直接拥有B类中的属性和方法。我们 就把A类叫B类的子类(派生类),把B类叫做A类的父类(基 类)。OC中的继承为单继承。   
        3. 继承是一种关系:继承是类与类之间的关系,是一种“is   a”关系。狗是动物  狗:动物 
      4.方法的重写 : 如果重写父类的方法,优先调用子类的方法,如果子类没有 重写父类的方法,则调用父类的方法
      5.继承的优缺点  
     1.提高了程序的复杂度,维护性和扩展性降低  
     2.破坏类的封装性  
    6.为什么使用继承   
    1.代码复用  
    2.制定规则  
    3.为了多态
    完整程序:
    TRAnimal.h
    #import <Foundation/Foundation.h>
               //子类  继承   父类
    //子类将拥有父类所有的属性和方法
    @interface TRAnimal : NSObject
    @property(nonatomic,assign)int age;
    -(void)eat;
    
    @end
    TRAnimal.m
    #import "TRAnimal.h"
    
    @implementation TRAnimal
    -(void)eat{
        NSLog(@"%d岁的狗狗嗅一下",self.age);
    }
    @end
    TRCat.h
    TRCat.m
    -(void)eat{
        NSLog(@“喵喵喵);//方法的重写(方法名相同、参数类型相同)优先调用子类
    }
    TRDog.h
    TRDog.m
    以上的TRDog继承了TRAnimal的特性,只需在创建类的时候把NSObject改为TRAnimal父类
    main.m
    #import <Foundation/Foundation.h>
    #import "TRAnimal.h"
    #import "TRDog.h"
    
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            TRAnimal* animal=[[TRAnimal alloc]init];
             animal.age=3;
            [animal eat];
            
            TRDog* dog=[[TRDog alloc]init];
            dog.age=2;
            [dog eat];
    
            TRCat* dog=[[TRCat alloc]init];
            [cat eat];
        }
        return 0;
    }
    结果:
    3岁的狗狗嗅一下
    2岁的狗狗嗅一下
    喵喵喵
    
    3.组合(一体机)
    1.表示两个对象之间是整体和部分的强关系,是“contains- a”关系  
    2.部分的生命周期不能超越整体  
    TRCpu.h
    #import <Foundation/Foundation.h>
    
    @interface TRCpu : NSObject
    -(void)run;
    @end
    TRCpu.m
    #import "TRCpu.h"
    
    @implementation TRCpu
    -(void)run{
        NSLog(@"cpu运行了");
    }
    @end
    TRComputer.h
    #import <Foundation/Foundation.h>
    #import "TRCpu.h"
    @interface TRComputer : NSObject
    -(void)powerOn;
    -(void)start;
    -(id)init;
    @end
    TRComputer.m
    #import "TRComputer.h"
    @interface TRComputer()
    @property(nonatomic,retain)TRCpu* cpu;
    @end
    
    @implementation TRComputer
    -(id)init{
        self = [super init];
        if (self) {
            self.cpu = [[TRCpu alloc]init];组合体现
        }
        return self;
    }
    -(void)powerOn{
        NSLog(@"接通电源");
        [self.cpu run];
        [self start];
    }
    -(void)start{
        NSLog(@"开始使用电脑");
    }
    @end
    
    main.m
    #import <Foundation/Foundation.h>
    #import "TRComputer.h"
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            //一体机
            TRComputer *computer = [[TRComputer alloc]init];
            [computer powerOn];
            
        }
        return 0;
    }
    结果:
    接通电源
    cpu运行了
    开始使用电脑
    
    4.聚合(台式机)
    1.表示两个对象之间是整体和部分的弱关系,是“has  a”关系   
    2. 部分的生命周期可以超越整体  
    TRCpu.h
    TRCpu.m
    同上
    TRComputer.h
    #import <Foundation/Foundation.h>
    #import "TRCpu.h"
    @interface TRComputer : NSObject
    @property(nonatomic,retain)TRCpu* cpu;
    -(void)powerOn;
    -(void)start;
    @end
    TRComputer.m
    #import "TRComputer.h"
    
    @implementation TRComputer
    -(void)powerOn{
        NSLog(@"接通电源");
        [self.cpu run];
        [self start];
    }
    -(void)start{
        NSLog(@"开始使用电脑");
    }
    @end
    main.m
    #import <Foundation/Foundation.h>
    #import "TRCpu.h"
    #import "TRComputer.h"
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            //台式机
            TRCpu *cpu = [[TRCpu alloc]init];
            TRComputer *computer = [[TRComputer alloc]init];
            computer.cpu = cpu;
            [computer powerOn];
                }
        return 0;
    }
    结果:
    接通电源
    cpu运行了
    开始使用电脑
    
    知识点
    十七、多态
    
    1.多种形态,包括引用多态、方法多态。
        a.引用多态
            父类的引用可以指向本类对象
            父类的引用也可以指向子类对象
        b.方法多态 (如果引用指向子类对象)
            如果子类重写了父类的方法,则优先调用子类的方法
            如果子类没有重写父类的方法,则调用父类的方法
        多态的引用只能调用父类的共享属性、方法,不能调用子类独有的方法
    2.好处:可以让我们设计更合理的代码,使用代码更通用,使用程序的 
                 可维护性和可扩展性更强
    例:
    TRAnimal.h
    #import <Foundation/Foundation.h>
    
    @interface TRAnimal : NSObject
    -(void)eat;
    @end
    TRAnimal.m
    #import "TRAnimal.h"
    
    @implementation TRAnimal
    -(void)eat{
        NSLog(@"动物具有吃的能力");
    }
    @end
    "TRDog.h
    #import "TRAnimal.h"
    
    @interface TRDog : TRAnimal
    -(void)watchDoor;
    @end
    "TRDog.m
    #import "TRDog.h"
    
    @implementation TRDog
    -(void)watchDoor{
        NSLog(@"狗是有看家的能力的");
    }
    -(void)eat{
        NSLog(@"狗是吃骨头的");
    }
    
    @end
    main.m
    #import <Foundation/Foundation.h>
    #import "TRAnimal.h"
    #import "TRDog.h"
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            //XX对于一个引用变量,可以指向任何类的对象
            //多态:引用多态 父类引用可以指向本类对象或子类对象
            TRAnimal *animal = [[TRAnimal alloc]init];
            TRAnimal *animal2 = [[TRDog alloc]init];
            //多态的引用只能调用父类的共享属性、方法,不能调用子类独有的方法
            //[animal2 watchDoor];
            //多态:方法多态
            [animal eat];
            //如果子类重写了父类的方法,优先调用子类的方法,如果子类没有重写父类的方法,则调用父类的方法
            [animal2 eat];
        }
        return 0;
    }
    
    2.多态可以用于数组
        代码可以灵活处理一系列的数据
        TRTransportation* trans[3] = {tran1,tran2…};
    例:
    @autoreleasepool {
            TREmployee *e1 = [TRManager managerWithName:@"zhangsan" andJob:@"coder" andSalary:8000.0f];
            TREmployee *e2 = [TRManager managerWithName:@"li" andJob:@"tester" andSalary:6500.0f];
            TREmployee *e3 = [TRStaff staffWithName:@"wangwu" andJob:@"coder" andSalary:6000.0f];
            TREmployee *e4 = [TRStaff staffWithName:@"zhaoliu" andJob:@"tester" andSalary:4500];
            //多态可以使用在数组中
            //引用多态
            TREmployee* emps[4]={e1,e2,e3,e4};
            for (int i=0; i<4; i++) {
                [emps[i] show];//方法多态
            }
    
    3.多态可以用于方法的参数(最终的类)
        方法可以灵活处理一系列的参数
    TRTaxi.h
    #import "TRTransportation.h"
    
    @interface TRTaxi : TRTransportation
    
    @end
    TRTaxi.m
    #import "TRTaxi.h"
    
    @implementation TRTaxi
    -(void)show{
        NSLog(@"交通工具为的士");
    }
    @end
    TRBus.h
    #import "TRTransportation.h"
    
    @interface TRBus : TRTransportation
    
    @end
    TRBus.m
    #import "TRBus.h"
    
    @implementation TRBus
    -(void)show{
        NSLog(@"交通工具为巴士");
    }
    @end
    
    TRBike.h
    #import "TRTransportation.h"
    
    @interface TRBike : TRTransportation
    
    @end
    TRBike.m
    #import "TRBike.h"
    
    @implementation TRBike
    -(void)show{
        NSLog(@"交通工具为自行车");
    }
    @end
    TRStudent.h
    #import <Foundation/Foundation.h>
    #import "TRTransportation.h"
    @interface TRStudent : NSObject
    -(void)gotoSchoolByTran:(TRTransportation*)tran;
    @end
    
    TRStudent.m
    #import "TRStudent.h"
    
    @implementation TRStudent
    //参数多态
    -(void)gotoSchoolByTran:(TRTransportation*)tran{
        NSLog(@"学生上学乘坐:");
        [tran show];
    }
    @end
    TRTransportation.h
    #import <Foundation/Foundation.h>
    
    @interface TRTransportation : NSObject
    -(void)show;
    @end
    
    TRTransportation.m
    #import "TRTransportation.h"
    
    @implementation TRTransportation
    -(void)show{
        NSLog(@"显示交通工具的信息");
    }
    @end
    main.m
    #import <Foundation/Foundation.h>
    #import "TRTransportation.h"
    #import "TRTaxi.h"
    #import "TRBus.h"
    #import "TRBike.h"
    #import "TRStudent.h"
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            TRTransportation* tran = [[TRTaxi alloc]init];
            TRBus *bus = [[TRBus alloc]init];
            
            TRBike *bike = [[TRBike alloc]init];
            TRStudent *stu = [[TRStudent alloc]init];
            [stu gotoSchoolByTran:bike];
            
        }
        return 0;
    }
    结果:
    学生上学乘坐:
    交通工具为自行车
    4.多态可以用于方法的返回值类型 (第二大类)
        方法的返回值类型更加灵活,可以返回一系列对象
    例:
    其他文件内容不变,改以下:
    TRTransportation.h
    #import <Foundation/Foundation.h>
    typedef enum{BIKE,BUS,TAXI} type;
    @interface TRTransportation : NSObject
    +(TRTransportation*)getTranByNum:(type)t;
    -(void)show;
    @end
    TRTransportation.m
    #import "TRTransportation.h"
    #import "TRBike.h"
    #import "TRBus.h"
    #import "TRTaxi.h"
    @implementation TRTransportation
    +(TRTransportation*)getTranByNum:(type)t{
        switch (t) {
            case BIKE:
                return [[TRBike alloc]init];
                break;
            case BUS:
                return [[TRBus alloc]init];
                break;
            case TAXI:
                return [[TRTaxi alloc]init];
                break;
            default:
                return nil;
                break;
        }
    }
    -(void)show{
        NSLog(@"显示交通工具的信息");
    }
    @end
    main.m
    #import <Foundation/Foundation.h>
    #import "TRTransportation.h"
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            TRTransportation *tran = [TRTransportation getTranByNum:TAXI];
            [tran show];
            
            
        }
        return 0;
    }
    结果:
    交通工具为的士
    
    作业:
    练习:重构
    1.写出以下类,用最少的代码解决问题。
                                TRShape形状类
                    |—————+—————|
        TRRectangle矩形x,y    TRCircle圆形r
                    |
        TRSquare正方形x
        求:周长perimeter与面积area,show方法查看周长和面积。(输出显示)
                  要使用属性、初始化方法、工厂方法、内存管理、继承。
    
    2.创建一个TREmployee类,TRStaff普通职员,TRManager领导,工资salary、工种job、姓名name,方法输出个人信息show方法,如果相应的工种领导的工资会比较普通职员高2000。TRHR类,人力资源,通过参数来招人,最少代码解决。(初始化方法、工厂方法、内存管理)
        1.软件工程师coder 6000 2.测试工程师4500 3.高级软件工程师8000
        4.软+领                     5.测+领                   6.高软+领
    查看所有员工的信息?(TRHR通过工厂方法,多态返回值给TREmployee)
    TRHR.h
    #import <Foundation/Foundation.h>
    #import "TREmployee.h"
    @interface TRHr : NSObject
    //工厂方法
    +(TREmployee*)hrWithNum:(int)num;
    @end
    TRHR.m
    #import "TRHR.h"
    #import "TRStaff.h"
    #import "TRManager.h"
    @implementation TRHr
    +(TREmployee *)hrWithNum:(int)num{
        switch (num) {
            case 1:
                return [[TRStaff alloc]initWithName:@"张三" andJob:@"软件工程师" andSalary:6000.0f];
                break;
            case 2:
                return [[TRStaff alloc]initWithName:@"李四" andJob:@"测试工程师" andSalary:4500.0f];
                break;
            case 3:
                return [[TRStaff alloc]initWithName:@"王五" andJob:@"高级软件工程师" andSalary:8000.0f];
                break;
            case 4:
                return [[TRManager alloc]initWithName:@"赵六" andJob:@"软件工程师领导" andSalary:6000.0f];
                break;
            case 5:
                return [[TRManager alloc]initWithName:@"钱七" andJob:@"测试工程师领导" andSalary:4500.0f];
                break;
            case 6:
                return [[TRManager alloc]initWithName:@"黑八" andJob:@"高软件工程师领导" andSalary:8000.0f];
                break;
            default:
                return nil;
                break;
        }
    }
    @end
    main.m
        @autoreleasepool {
            TREmployee* emps[3];
            
            TREmployee* emp1 = [TRHr hrWithNum:1];
            TREmployee* emp2 = [TRHr hrWithNum:4];
            TREmployee* emp3 = [TRHr hrWithNum:2];
            emps[0] = emp1;
            emps[1] = emp2;
            emps[2] = emp3;
            
            for (int i = 0; i<3; i++) {
                [emps[i] print];
            }
            
        }
    
    3./*创建一个Person类,show方法,*/查看艺术品的详细信息。print查看当前艺术品的详细。创建三个艺术品,分别查看它们的信息。
    艺术品名称product 作者author 年代year
    演唱者singer 时长time 人数count
                                Arts艺术品(父类)多态参数返回给Person类
                   |—————+—————|
            Painting(油画)               Music(音乐)
                                              |———+——|
                                                    Pop(流行音乐) Rock(摇滚)
    TRPerson.h
    #import <Foundation/Foundation.h>
    #import "TRArts.h"
    @interface TRPerson : NSObject
    -(void)show:(TRArts*)art;
    @end
    TRPerson.m
    #import "TRPerson.h"
    
    @implementation TRPerson
    -(void)show:(TRArts*)art{
        [art print];
    }
    @end
    main.m
      @autoreleasepool {
            TRArts *a1 = [TRPainting paintingWithProduct:@"蒙娜丽莎" andAuthor:@"达芬奇" andYear:1780];
            //[a1 print];
            TRArts *a2 = [TRPop popWithProduct:@"小苹果" andAuthor:@"筷子兄弟" andYear:2014 andSinger:@"筷子兄弟" andTime:3.5f];
            //[a2 print];
            TRArts *a3 = [TRRock rockWithProduct:@"尽情摇摆" andAuthor:@"未知" andYear:2000 andSinger:@"Beyond" andTime:4.5 andCount:5];
            //[a3 print];
            TRArts* arts[3] = {a1,a2,a3};
            TRPerson *person = [[TRPerson alloc]init];
            for (int i=0; i<3; i++) {
                [person show:arts[i]];
            }
            
        }
    
    
    二、协议
    xcode6
    source->OC File->type(protocol)
    1.协议Protocol
        协议指的是双方(苹果公司,程序员)的约定。
        遵守一个约定,就等增强类的功能。
    
        双方(程序员,程序员)
        a.协议语法:
            @protocol 协议名<父协议>
                @required(默认)
                    必须遵守的属性或方法
                    drive;方法
                @optional
                    可以遵守的属性或方法
            @end
        b.遵守协议
            (1)类必须遵守协议
                @interface 类名:父类名<协议>
            (2)必须协议的方法
                在.m文件中,必须实现协议中要求的方法
        c.协议的使用
            父类引用可以指向子类(类型)的对象
            协议引用可以指向任意类(类型)的对象(遵守协议)(方法属性)
            //任意类型
            id<协议> p = 对象<遵守协议实现方法>;
            只能调用协议中定义的方法
            [p 协议中的方法消息];
            p.协议中的属性;
        d.协议的引用
            可以用在数组,可以用在参数,也可以用在返回值类型。
    TRProtocol.h
    #import <Foundation/Foundation.h>
    //协议中 只有方法的声明 没有方法的实现
    @protocol TRProtocol <NSObject>//协议名称    默认@required
    -(void)method;
    @end
    TRMyClass.h
    #import <Foundation/Foundation.h>
    #import "TRProtocol.h"
    //遵守协议 必须实现协议中的方法
    @interface TRMyClass : NSObject<TRProtocol>
    -(void)method2;
    @end
    TRMyClass.m
    #import "TRMyClass.h"
    
    @implementation TRMyClass
    -(void)method2{
        NSLog(@"类自己的方法");
    }
    -(void)method{
        NSLog(@"实现了协议的方法");
    }
    @end
    main.m
    #import <Foundation/Foundation.h>
    #import "TRProtocol.h"
    #import "TRMyClass.h"
    int main(int argc, const char * argv[])
    {
        @autoreleasepool {
            //协议引用
            //协议引用可以指向任意"类型"遵守了协议的对象
            id<TRProtocol> p = [[TRMyClass alloc]init];
            //通过协议引用 可以调用协议中的方法
            [p method];
            //只能调用协议方法,不可以调用类方法
            //[p method2];
            //用于数组、参数、返回值类型
        }
        return 0;
    }
    结果:
    实现了协议的方法
    
    1.协议与多态
        1.多态关注的是类的类型,
        2.而协议并不关注类的类型,关注的是类的方法和属性
    2.协议的继承
        1.协议的继承相当于协议的合并
        2.协议的引用只能调用协议中声明的方法或属性。
    例:
    TRTarena1.h
    #import <Foundation/Foundation.h>
    
    @protocol TRTarena1 <NSObject>
    -(void)study;
    @end
    TRTarena2.h
    #import <Foundation/Foundation.h>
    #import "TRTarena1.h"
                //子协议 继承 父协议
    @protocol TRTarena2 <TRTarena1>
    -(void)learn;
    @end
    
    TRStudent.h
    #import <Foundation/Foundation.h>
    #import "TRTarena2.h"
    @interface TRStudent : NSObject<TRTarena2>
    
    @end
    TRStudent.m
    #import "TRStudent.h"
    
    @implementation TRStudent
    -(void)learn{
        NSLog(@"子协议中要求的方法");
    }
    -(void)study{
        NSLog(@"父协议中要求的方法");
    }
    @end
    main.m
    #import <Foundation/Foundation.h>
    #import "TRTarena1.h"
    #import "TRTarena2.h"
    #import "TRStudent.h"
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            //协议的引用只能调用协议中声明的方法
            id<TRTarena1> p = [[TRStudent alloc]init];
            [p study];
            //协议的继承,相当于协议的合并
            //协议的引用只能调用协议中声明的方法
            id<TRTarena2> p2 = [[TRStudent alloc]init];
            [p2 learn];
            [p2 study];
        }
        return 0;
    }
    结果:
    父协议中要求的方法
    子协议中要求的方法
    父协议中要求的方法
    3.多个协议
    一个类可以遵守多个协议,也相当于协议的合并
       @interface 类 :父类<协议1,协议2>
    TRStudent.h遵守协议的时候
    #import <Foundation/Foundation.h>
    #import "TRTarena6.h"
    #import "TRTarena2.h"
    @interface TRStudent : NSObject<TRTarena2,TRTarena6>
    4.**协议中要求的属性,我们在遵守的时候要合成一下属性
    5.协议也可以与类定义在一个文件中(只需将协议中的内容复制到类的定义中)
    TRStudent.h
    #import <Foundation/Foundation.h>
    #import "TRTarena6.h"
    //#import "TRTarena2.h"
    
    #import <Foundation/Foundation.h>//遵守协议时只需将协议TRTarena2中的文件复制过来
    @protocol TRTarena2 <NSObject>
    @end
    
    @interface TRStudent : NSObject <TRTarena6>
    @end
    知识点
    七、分类
    增强类能力
      a.继承:优点与缺点都继承了
      b.协议:要修改源代码
      c.分类:可以灵活的给指定的类添加能力,不需要修改源代码 
    一、分类
    
      1.语法规则:
          分类文件命名:  主类类名+分类类名
        #import "TRPerson+TRWeapon.h"
      2.  *.h文件存放分类的声明部分内容  
             @interface  主类类名(分类类名)  
                 //添加方法声明  
             @end*.m文件存放分类的实现部分内容  
               @implementation  主类类名(分类类名)         
                     //添加方法实现  
           @end3.在主函数中导入分类头文件, 主类对象既可以调用分类的方法
    **注:1.分类中是不可以声明实例变量的,自然也不可以创建属性
                2. 在分类中是可以访问主类的属性,也可以访问主类的实例变
    TRPerson.h
    #import <Foundation/Foundation.h>
    
    @interface TRPerson : NSObject
    {
        int _i;//主类中声明实例变量
    }
    @property int i;//主类中声明属性
    -(void)job;
    @end
    TRPerson.m
    #import "TRPerson.h"
    
    @implementation TRPerson
    @synthesize i = _i;//主类中合成实例变量
    -(void)job{
        NSLog(@"具有工作的能力");
    }
    @end
    TRPerson+TRWeapon.h
    #import "TRPerson.h"
                //主类类名 分类类名
    @interface TRPerson (TRWeapon)
    {
        //int _i;//分类中不可以添加实例变量
    }
    //@property int i;//分类中属性是没有意义的
    -(void)fire;
    @end
    TRPerson+TRWeapon.m
    #import "TRPerson+TRWeapon.h"
    @implementation TRPerson (TRWeapon)
    //@synthesize i = _i;//
    -(void)fire{
        _i = 10;//分类中是可以访问主类的实例变量
        self.i = 20;//分类中是可以访问主类的属性
        NSLog(@"具有了开火的能力");
    }
    @end
    main.m
    #import <Foundation/Foundation.h>
    #import "TRPerson.h"
    #import "TRPerson+TRWeapon.h"
    #import "NSString+TRConnection.h"
    int main(int argc, const char * argv[])
    {
        @autoreleasepool {
            TRPerson *person = [[TRPerson alloc]init];
            [person job];
            [person fire];
            
                }
        return 0;
    }
    具有工作的能力
    具有了开火的能力
    2.给系统类添加分类
    *分类不但可以给自己添加分类,还可以给系统添加分类。
       可以给系统提供的类,如NSObject、NSString等,添加分类
            NSString+TRFunction.h
    如:NSString* n=[[NSString alloc]init];
            [n function];
    二、扩展
          1.扩展是一个特殊的分类。没有扩展名。
        2.保存的文件命名:
            主类类名_扩展的文件名.h  只有.h文件
            TRPerson_TRExtension.h
        3.***扩展只能在类的.m文件中使用
        4.可以给一个类添加私有的实例变量、方法、属性
    例:
    TRPerson.h
    #import <Foundation/Foundation.h>
    
    @interface TRPerson : NSObject
    {
        int _i;
    }
    @property int i;
    -(void)job;
    @end
    TRPerson.m
    #import "TRPerson.h"
    //#import "TRPerson_TRExtension.h"
    @interface TRPerson ()//同上,只是复制过来
    {
        int _i2;//扩展中声明实例变量
    }
    -(void)method;//扩展中添加的方法
    @property int i2;
    @end
    
    
    @implementation TRPerson
    @synthesize i = _i;
    -(void)method{
        _i2 = 10;
        //self.i2 = 20;
        NSLog(@"添加一个私有的方法。%d",self.i2);
    }
    
    //类本身具有的方法
    -(void)job{
        //_i = 30;
        self.i = 40;
        NSLog(@"具有工作的能力%d",self.i);
    }
    @end
    TRPerson_TRExtension.h
    #import "TRPerson.h"
    
    @interface TRPerson ()
    -(void)method;//添加的方法
    @end
    main.m
    #import <Foundation/Foundation.h>
    #import "TRPerson.h"
    #import "TRPerson_TRExtension.h"
    
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            TRPerson *p=[[TRPerson alloc]init];
            [p job];
            [p method];
              }
        return 0;
    }
    结果:
    具有工作的能力40
    添加一个私有的方法。10
    • 分类与扩展的区别    
    - 分类:是不可以声明实例变量,通常是公开的,文件名通常 为:"主类类名+分类类名.h”  
    - 扩展:是可以声明实例变量,是私有的,文件名通常 为:“主类类名_扩展标识.h”,注意没有扩展名的
    
    知识点
    八、ARC内存管理
    1.强引用:(__strong)  强引用指向对象的时候,会自动通知引用计数器加1,当超出强引用的作用域,会自动通知引用计数器减1。(系统默认为强引用)
    TRStudent.h
    #import <Foundation/Foundation.h>
    
    @interface TRStudent : NSObject
    -(void)study;
    @end
    TRStudent.m
    #import "TRStudent.h"
    
    @implementation TRStudent
    -(void)study{
        NSLog(@"学生具有学习的能力");
    }
    -(void)dealloc{
        NSLog(@"学生对象销毁了");
    }
    @end
    
    main.m
    #import <Foundation/Foundation.h>
    #import "TRStudent.h"
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            __strong TRStudent *stu2 = nil;
            if (1==1) {
                //默认就是强引用
                TRStudent *stu = [[TRStudent alloc]init];//通知引用计数器为1
                stu2 = stu;//RC:1+1=2 retain
                NSLog(@"代码块末尾");
            }//通知引用计数器减1 RC:2-1
            [stu2 study];
        }//RC:1-1=0 销毁了
        NSLog(@"程序末尾");
        return 0;
    }
    结果:
    代码块末尾
    学生具有学习的能力
    学生对象销毁了
    程序末尾
    
    2.弱引用:(__weak)仅仅的是指向对象,并不会通知引用计数器做加1或减1操作。而且不存在野指针问题,当对象不存在的时候,弱引用会自动置空。
    **注意:创建对象时候,不可使用弱引用。
    3. _unsafe_unretain关键字
       1.@property(nonatomic,unsafe_unretained)int  age;  
       2.-   unsafe_unretained等同于“assgin”,功能和__weak几乎 一样,唯一不同,没  有“zeroing  weak  reference”,通 常使用在基本数据类型
    4.ARC与MRC混编
    (1)手动把MRC的代码转换成ARC的代码  
       retain=>strong   release、autorelease、[super  dealloc]删除掉
    (2)自动将MRC转换成ARC的功能
           1.由 xcode帮我们删掉相应的方法:
                菜单栏(Edit)->Refacotor(重构)->Convert  to   Objective-C  ARC
                  恢复到MRC:File->Restore snapshot……
            2.通知编译器继续编译MRC代码:
       项目栏->Build Phases->Compile Sources(1 item)->选择文件双击->- fno-objc-arc
       恢复到MRC:-fobjc-arc
  • 相关阅读:
    echo "不允许上传该类型的文件
    php构造函数,引入数据库操作类函数
    php函数描述及例子
    php如何判断远程文件是否存在
    多线程面试题系列(16):多线程十大经典案例之一 双线程读写队列数据
    多线程面试题系列(15):关键段,事件,互斥量,信号量的“遗弃”问题
    多线程面试题系列(14):读者写者问题继 读写锁SRWLock
    多线程面试体系列(13):多线程同步内功心法——PV操作下
    多线程面试题系列(12):多线程同步内功心法——PV操作上
    多线程面试题系列(11):读者写者问题
  • 原文地址:https://www.cnblogs.com/52190112cn/p/5063114.html
Copyright © 2020-2023  润新知