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

iOS9基础知识(OC)笔记的更多相关文章

  1. Objective-c基础知识学习笔记

    Objective-c基础知识学习笔记(一) 一直有记录笔记的习惯.但非常久没分享一些东西了,正好上半年開始学习IOS了,如今有空写点.因开发须要,公司特意为我们配置了几台新MAC.还让我们自学了2周 ...

  2. Python基础知识总结笔记(四)函数

    Python基础知识总结笔记(四)函数python中的函数函数中的参数变量作用域偏函数PFA递归函数高阶函数BIFs中的高阶函数匿名函数lambda闭包Closure装饰器Decorator函数式编程 ...

  3. 〖前端开发〗HTML/CSS基础知识学习笔记

    经过一天的学习,把慕课网的HTML/CSS基础知识学完了,笔记整理: 1. 文件结构: HTML文件的固定结构: <html> <head>...</head> & ...

  4. java基础知识学习笔记

    本文知识点以js为参照.对比分析得出笔记.JavaScript之所以叫JavaScript是打算借助java推广自己.虽然都是开发语言,但JavaScript一开始主要运行在 客户端,而java主要运 ...

  5. ios9基础知识总结(foundation)笔记

    类:NSObject .NSString.NSMutableString.NSNumber.NSValue.NSDate.NSDateFormatter.NSRange.Collections:NSS ...

  6. 015-OC基础语法-OC笔记

    学习目标 1.[了解]Objective-C语言简介 2.[掌握]第一个OC程序 3.[掌握]OC中的字符串 4.[熟悉]OC中的一些玩意 5.[了解]面向过程与面向对象 6.[掌握]类的声明和实现 ...

  7. Java多线程基础知识总结笔记

    本篇笔记记录一些在Java多线程编程中常见的关键字,比较简单和基础的就不写太详细了. 一.Thread类(其实也是应用了Runnable接口)和Runnable接口(只有一个run方法,应用该类必须重 ...

  8. 传智播客 Html基础知识学习笔记

    HTML基础 <p></p>标志对用来创建一个段落,,<p>标志还可以使用align属性, 它用来说明对齐方式 语法是:<p align="&quo ...

  9. ios9基础知识(UI)总结

    UIWindow.UILabel.UIColor.UIScreen.UIViewController.UIView.UIControl.UIButton.IBOutlet.IBAction.UISte ...

随机推荐

  1. Oracle自治事务

    定        义: Autonomous transactions are independent transactions that can be called from within anot ...

  2. XML 解析中,如何排除控制字符

    XML 解析中,如何排除控制字符 今天在解析一个中文的 XML时,始终报错 PCDATA invalid Char value 21 in Entity ,查询了一下这个 21 的ascii 值,发现 ...

  3. (转)ubuntu下如何查看软件安装目录以及安装版本

    1.查询版本 aptitude show 软件名 例如:aptitude show kde-runtime 显示如下: ****@ubuntu:~$ aptitude show kde-runtime ...

  4. 飘逸的python - 多条件排序及itemgetter的应用

    曾经客户端的同事用as写一大堆代码来排序,在得知python排序往往只需要一行,惊讶无比,遂对python产生浓厚的兴趣. 之前在做足球的积分榜的时候需要用到多条件排序,如果积分相同,则按净胜球,再相 ...

  5. UML中九种图的理解

    1.用例图. 用例图是用来描述用户需求的,从用户的角度来描述系统的功能,并指出各个执行者.强调谁在使用,系统的执行者是谁. 2.类图. 用来定义系统中的类,包括描述类的结构和类之间的关系.类图的主要作 ...

  6. 如何让EcStore和微博同步来推广网站

    EcStore是创建B2C商城的首选PHP系统,它功能强大.操作方便,安装后马上就能建立起一个自己的B2C商城,但建好后如何推广运营商城却不是件容易的事. 新浪微博用户数量大.传播速度快,互联网上拥有 ...

  7. 为编写网络爬虫程序安装Python3.5

    1. 下载Python3.5.1安装包1.1 进入python官网,点击menu->downloads,网址:https://www.python.org/downloads/ 1.2 根据系统 ...

  8. PyQt4.11.3(python3.4+QT4)ui文件生成py文件

    最近开始接触学习Python,所以想用QT弄个窗体程序出来玩玩,环境是Python3.4.2.PyQt4.11.3-Py3.4.Win7.用PyQt自带的Designer设计出一个窗体ui文件后,需要 ...

  9. Android应用开发中Intent的作用及使用方法

    Intent是一种运行时绑定(run-time binding)机制,它能在程序运行过程中连接两个不同的组件.通过Intent,你的程序可以向Android表达某种请求或者意愿,Android会根据意 ...

  10. Ext4报错Uncaught Ext.Loader is not enabled

    提示: Uncaught Ext.Loader is not enabled, so dependencies cannot be resolved dynamically. Missing requ ...