iOS9基础知识(OC)笔记

1月16日

 

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  主类类名(分类类名)         

                 //添加方法实现  
           @end  

  3.在主函数中导入分类头文件, 主类对象既可以调用分类的方法

**注: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

 

posted @ 2015-12-14 20:00  乌托邦小余  阅读(436)  评论(0编辑  收藏  举报