Objective-C汇总
Objective C(20世纪80年代初)
一、OC语言概述
.1985年,Steve Jobs成立了NeXT公司
.1996年,12月20日,苹果公司宣布收购了NeXT software 公 司,NEXTSTEP环境为apple公司下主要开发、发行操作 系统OSX的基础,这个开发环境的版本被苹果公司命名为 Cocoa(可可)框架
NSString NS=NEXTSTEP
.Cocoa框架 (Cocoa Touch框架 ->Ctapp )
.Fundation框架,基础框架,包括:字符串、数字、数组、 字典、集合等
框架名称 头文件
#import <Foundation/Foundation.h>
.Application Kit框架,应用程序工具箱,它包括了实现程 序图形、事件驱动和用户界面的全部对象,窗口、对话框、按 钮、菜单、滚动条、文本框等,而且这个列表还在不断的添加
二、OC与C区别
.创建项目的时候,type—>Foundation(OC)
.main.c->main.m(源代码)
.#include <stdio.h> -> #import <Foundation/Foundation.h>
.在OC的开发环境中,是兼容C的语法
.printf()—>NSLog(@….);日志输出
. 编译原理OC与C是一样的,只不过编译命令由原来的gcc->clang。eg:clang -framework Foundation main.m
三、逻辑数据类型BOOL
OC中的逻辑值类型:
.BOOL b2 = YES;//*YES 1 NO 0
.不用导入头文件
//C中的逻辑值类型
bool isBool = false;
//***OC中的逻辑值类型
BOOL isBool2 = YES;
if (isBool2) {
NSLog(@"条件成立!");
}else{
NSLog(@"条件不成立!");
}
结果:条件成立!
三、OC中的函数
练习:求两个数的关系 a是否大于b
.函数实现 返回值(逻辑类型值)
.在main函数中传入两个值并得到结果
.通过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=,b=;
BOOL isFlag=bu(a,b);
if (isFlag) {
NSLog(@"%d>%d",a,b);
}
else{
NSLog(@"%d<%d",a,b);
} }
return ;
}
结果:<
四、什么是面向对象程序开发
.面向过程
数据结构 + 算法
.面向对象
属性 + 行为
计算机中的对象Student: (有什么+能干什么)
属性(成员) age,name
方法(函数)study()
如:现实中周边一个对象 -> 计算机中对象?
学生 Student
有什么: 姓名、年龄 属性:name、age
能什么: 学习 方法:study()
五、类与对象(抽象事物,内存中不存在)
.类是对象还未产生时,将要是什么样,具有相同属性和行为方法的同一类元素的总称
.对象就是类经过实例化所产生的一个内存趋于数据
*必须先有类经过实例化才会产生对象,程序需要的是具体的数据,所以程序在执行过程当中,需要的对象。
.第一个面向对象程序:
. 类(文件中的代码)
在计算机中每一个类被存在两个文件中:
一、.h声明….属性/方法(属性没有实现,只有声明)
@interface Student : NSObject //类名Student
@property int age;//声明属性
-(void)study;//声明方法 @end
二、 .m实现....方法
@implementation Student //方法的定义、实现
-(void)study{
NSLog(@"学生执行了study方法"); }
@end
.实例化(main.m文件 )
类—>对象
在需要使用对象的地方实例化
.导入头文件
#import "Student.h"
.对一个类进行实例化
[类 alloc] 实例化得到一个内存(堆)的首地址
[Student alloc]
通过类发送alloc,通过一个类创建对象,通过stu变量,找 到内存的对象
//给类Student 发消息alloc会创建出一个Student类型的对象
.Student* stu=[Student alloc]实例化;stu就是对象
.操作对象
属性:给属性赋值或取属性的值
对象.属性=......;//赋值
…=对象.属性;//取值
方法:
[对象 方法名]调用对象的方法
***完整程序
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=;//属性赋值
[stu study];//调用对象的方法 //发送一个消息
NSLog(@"age:%d",stu.age);//得到属性值 }
return ;
}
结果:
学生有学习的能力!
age: 知识点
一、方法(实质是函数) • 什么是方法 (method)
代表一个对象可以干什么,一般来讲方法必须与对象结合使用 对象中内容分为属性和方法两部分 : - 属性是对象中的数据成员,用于描述对象的特征
- 方法是对象中的函数成员,用于描述对象的行为
.关于函数 . C语言的函数 返回类型 函数名(); .Oc中函数的一般格式: 类型标识 (返回值类型) 函数名:(参数类型)参数名;
+/- (void) show; int
语法格式:
.-(返回值类型)方法名; //无参方法
//无返回值 无参数的方法 method
-(void)method; .-(返回值类型)方法名:(参数类型)参数名;//有一个参数方法
//有一个参数的方法
//返回值类型 方法名:(参数的类型)参数名;
-(void)method2:(int)arg; .-(返回值类型)方法名:(参数类型1)参数名1 :(参数类型2)参数名2;//有两个参数的方法 -(void)method3:(int)age :(char)sex //需注意参数名后需加空格再加冒号 .-(返回值类型)方法名:(参数类型1)参数名1 :(参数类型2)参数名2 :(参数类型n)参数名n;//3…n…个参数
//返回值类型 方法名:(参数的类型)参数名 :(参数的类型)参数名 ...n;
/*定义一个方法,传多个参数:
参数1年龄、参数2性别、参数3学号
参数4工资、参数5家里有几个人。*/
() -(void)method3:(int)age
:(char)sex //需注意参数名后需加空格再加冒号
:(int)num
:(float)salary
:(int)count;
() -(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: andSex:'M' andNum: andSalary:2000.0f andCount:];
}
return ;
}
结果:
age: sex:M num: salary:2000.000000 count: .公有方法、私有方法
. 公有方法:即在.h文件中声明,又在.m文件实现。
可以在任意文件中使用。[对象 method];
.私有方法:没在.h文件中声明,但在.m文件实现。
只可以在当前(同一)文件中使用,即在main.m文件中不能使用。通过[self method]实现;
.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];//不能调用类的私有方法 不执行报错
结果:
公有方法执行了
私有方法执行了 .成员变量、实例变量
变量就是保存一个数据。
.成员变量将要保存什么数据。(_变量名)
@interface MyClass : NSObject { int _i;}//成员变量 //必须用大括号括起来 不能初始化 .实例变量真正保存什么数据。
.公有的实例变量与私有的实例变量,最大的区别就是在对象外可见和不可见。默认情况,都不可以直接进行操作。
.如果需要操作一个实例变量,目前的操作方式只有方法,通过方法来操作实例变量。(方法是操作实例变量的一种方式)。
如:
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:];//给实例变量赋值
NSLog(@"i:%d",[stu geti1]);//得到实例变量的值 }
return ;
}
结果:
i: 知识点
二、属性 是访问实例变量的一种方式。 .变量的访问修饰符
• 定义变量
– @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=;//package 这个项目里使用
myclass->_i3=;//public 其他的不能访问
}
return ;
} .属性
.属性是访问实际变量的一种方式
.属性有两个方法组成(setter/getter方法)。(属性是方法)
.属性本身不能保存数据,数据是由实例变量保存的 规范: 实例变量的命名:_开头
实例变量对应的属性:去掉下划线,首子母大写
如果认为规范不满意,自己重新合成 一、属性的本质三部分组成
a.实例变量
int _age
b.setter和getter方法的声明与实现
.)setter方法:方法名:“set”+属性名并首子母大写 +“:”+和属性类型一样的参数,无返回值。
-(void)setSex:(char)sex //_age去掉下划线首子母大写
.)getter方法:方法名和属性名一样,没有参数,返回值类型 和属性类型一样。
-(char)sex;
c.点语法
setter方法的实现主要用来给属性赋值的 getter方法的实现主要用来读取属性值的 对象.属性 = 值;=>会自动调用setter方法 变量 = 引用.属性;=>会自动调用getter方法
myclass.sex='m';//自动调用setter方法
myclass.age=;
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=;
NSLog(@"sex:%c age:%d",myclass.sex,myclass.age);//自动调用getter方法
}
return ;
}
结果:sex:m age:
二 、声明式属性
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=;
myclass.sex='f';
NSLog(@"age:%d sex:%c",myclass.age,myclass.sex);
}
return ;
}
结果:age: 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+; //同时调用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=;
myclass.sex='f';
NSLog(@"age:%d sex:%c",myclass.age,myclass.sex);
}
return ;
}
结果:age: sex:f
知识点
三、初始化 //在创建的时候,就可以确定对象的值,使用初始化方法更简单、直接
//当程序在执行过程当中,如果需要给属性赋值,就使用方法和*属性 *真正初始化对象是由父类解决的
self=[super init]//哪个对象执行的初始化操作,将结果给哪个对象本身(自己)
return self;//当初始化操作完毕之后,经结果返回。 .初始化(默认值)对象。(无参的初始化方法)
即使不定义无参的初始方法,对象本身也具备。
如果对原有的初始化方法不满意,是可以自定义的
.初始化(指定值)对象。(有参的初始化方法)
有参的初始化方法必须自定义。
.有参的都以“initWith...”开头(规定)
.初始化方法只能用一次
int i ;
int i = ;//默认值
int i = ;//指定值 [MyClass alloc];
[MyClass alloc]init];//默认值 无参的初始化方法
[MyClass alloc]initWithAge:];//指定值 有参的初始化方法 完整有参初始化方法程序:
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: andSex:'m' andNum:];
NSLog(@"age:%d sex:%c num:%d",student.age,student.sex,student.num); } return ;
}
结果: age: sex:m num:
*创建类的时候,加前缀,前缀大写,类名大写,加起来不超过4个
注意区分不同的知识点:实例变量_age 参数age 属性.age
.id类型 任意类型指针
id是一个指针,但在使用时无需加*,相当于void*
.self关键字
代表当前对象本身,还可以代表当前类
.[myclass method];
如果method方法中,有一个self关键字,self就相当于myclass对象本身。
.在对象的内部如果调用本身的属性,self.属性
如果调用本身的属性,[self 方法]
.super关键字 练习:
创建两个Point2对象,它有横坐标x,纵坐标y。
保存两个坐标值。
()普通方法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:];//普通方法赋值
[p1 setY:];
[p1 show];
结果:横坐标: 纵坐标:
()属性
<>属性本质
<>声明式属性
<>ios5
<>ios6 **show取值:
-(void)show{
.//普通方法中可以直接访问实例变量
//NSLog(@"横坐标:%d 纵坐标:%d",_x,_y);
.//getter方法也可以访问实例变量
//NSLog(@"横坐标:%d 纵坐标:%d",[self x],[self y]);
.//属性可以访问实例变量
NSLog(@"横坐标:%d 纵坐标:%d",self.x,self.y);
} ()初始化方法 知识点
四、实例方法、类方法
.方法分为两类:
.实例方法
-开头的方法,都是实例方法;
通过实例调用的方法
[myClass method];
.类方法
+开头的方法,都是类方法;
通过类调用的方法是类方法
[TRMyClass method2];
.实例方法
-实例方法就是对象方法
-实例方法必须在定义对象之后,由对象来调用
.类方法
-类方法就是静态方法 (代码区)
-类方法主要的使用就是用来创建对象的
- 类方法不能访问实例变量和属性,但类方法可以创建对象,通过对象访问实例变量和其属性
***类方法与实例方法区别
- 实例方法与实例有关系的,所以实例方法可以调用、读取实 例中的实例变量或属性。
- 类方法与实例无关系的,所以类方法不可以调用、读取实例 例中实例变量和属性。
- 在类方法中可以创建对象,当然访问该对象的实例变量和属 性。 .工厂方法
类方法用来创建对象的方法就是工厂方法
.无参工厂方法
创建对象,并给属性一个默认值。
+(TRStudent*)student{
return [[TRStudent alloc]init];
}
.有参工厂方法
.要依赖有参的初始化方法
-(id)initWithAge:(int)age;
.创建对象,并给属性一个指定的值
+(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: andSex:'F' andSalary:];
[stu show];
TRStudent* stu2=[TRStudent studentWithAge: andSex:'M' andSalary:];
[stu2 show]; //工厂方法使用
TRStudent* stu3=[TRStudent studentWithAge: andSex:'F' andSalary:];
[stu3 show]; }
return ;
}
结果:
age: sex:F salary:5600.000000
age: sex:M salary:5000.000000
age: sex:F salary:5500.000000 .单例模式(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 ;
}
结果:
0x100202ff0
0x100202ff0
知识点
五、MRC内存管理 .内存管理
在计算机中,堆内存的使用,是需要程序员手动创建,并且使用完毕
以后要手动销毁(回收),这个过程叫做内存管理。
在OC中,内存管理又有两种方式:
MRC:手动内存管理 完全由程序员控制
ARC:自动内存管理 由程序员通知编译,编译帮我们控制
• 进程空间 - 代码区:只读。 - 堆:自己创建、自己回收释放,对象是保存在堆区的。
- 全局区:进程启动时分配,进行结束时释放。 - 栈:局部变量,自动创建、自动释放空间
.MRC手动内存管理
注:ios6,强制使用ARC *改项目内存管理
.项目默认的内存管理是ARC,将内存管理改为MRC
项目—>Basic(选择ALL)—>右搜索(ARC)—>Apple LLVM 5.1-Language -Objective C (Automatic Reference Counting ) —>No
.由于程序在执行的时候,不一定立刻回收堆内存,可能会出现异常,也可能不会出现。
Edit Schema->Run…->Diag…->Mem…Manage…Objective-C Enabel Zombie Objects 打开 MRC手动管理引用计数器
Manual手动
Reference Counting引用计数器
一、程序通过代码通知引用计数器做加1或减1操作:
.向对象发送alloc、copy、new通知引用计数器加1.
在OC当对象不再使用时候,如果忘记发送release消息,内存溢出,资源浪费
.当对象不再使用,发送release通知引用计数器减1.
.当引用计数器为0时,会自动释放该对象的堆内存空间
.当对象销毁时,会自动执行dealloc方法
当对象销毁时,对象中的实例变量、方法均不可用,内存管理存在的问题
二、内存管理存在的问题:
()如果对象销毁,但引用的值还在存,此时存在野指针问题,使用空指针解决野指针问题。
并且对象的实例方法与实例变量不可使用,否则会报异常、crash。
()如果对象未销毁,此时存在内存泄漏问题,造成资源浪费。 .release和dealloc
.[stu release];//销毁对象,引用计数器减1,变为0,自动执行dealloc
.//当引用计数器为0时,会自动销毁对象
-(void)dealloc{
//真正的对象销毁由父类操作的
[super dealloc];}
.retainCount和retain
.[stu retainCount]//查看当前计数器的值RC
.[stu retain];//通知引用计数器加1
.[stu release];//通知引用计数器减1
//内存管理原则,哪里加1,就去哪里减1
.声明式属性
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 ;
}
结果:
count:
学生具有学习的能力
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 ;
}
结果:
RC:
学生具有学习的能力
学生具有学习的能力
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 = ;
TRStudent *stu = [[TRStudent alloc]init];
stu.book = sanguo;
[sanguo release];
[stu study];
[stu release];
//内存管理原则:哪里加1,哪里就有责任减1
}
return ;
}
结果:
学生具有学习的能力 看书:
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 = ;
//三1 水0 学0
TRBook *shuihu = [[TRBook alloc]init];
//三1 水1 学0
shuihu.price = ;
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 ;
}
结果:
学生具有学习的能力 看书:
TRBook销毁了
学生具有学习的能力 看书:
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
同上 .自动释放池(autorelease)
.可以通过自动释放池管理多个对象的release操作(仅一次)
.当自动释放池结束的时候,会向池中每个对象发送release消息
.注意两个问题:
a.一定要有代码块
@autoreleasepool{}
b.一定要手动将对象放入自动释放池中
[对象 autorelease ]
.使用场景:
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 ;
}
结果:
自动释放池末尾
对象销毁
对象销毁
程序末尾
练习:
学生和书的故事,可否属性的本质(setter/getter)来解决。工厂方法 .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。
.创建类、对象
第一次玩游戏 CS intelP3 1G hz KingMax 2G size
第二次玩游戏 战地4 IntelP4 2G hz KingMax2 8G size
.给类添加属性、初始化方法、工厂⽅法
.声明式属性⽅方式,解决内存问题。
完整程序:
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:];
TRMem *kingMax = [TRMem memWithSize:];
TRComputer *computer = [TRComputer computerWithCpu:intelP3 andMem:kingMax];
[computer playGame];
TRCpu *intelP4 = [[[TRCpu alloc]initWithHz:] autorelease];
TRMem *kingMax2 = [[[TRMem alloc]initWithSize:]autorelease];
computer.cpu = intelP4;
computer.mem = kingMax2;
[computer playGame]; }
return ;
}
结果:
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 知识点
六、面向对象的三大特性及封装
.封装
.将信息(属性、方法)封装在一个对象中,
只给外界公开访问的接口, 而且把具体实现隐藏起来
需要公开的内容在.h文件中声明,不需要公开的内容在.m文件中实现(隐藏源代码)
.好处:增强可读性、可维护性、可扩展性
)代码结构更清晰 )可以和第三方合作,但又保护了源代码,避免泄漏
.继承
.继承是一种代码复用技术,是类与类之间的一种关系(与内存关)。
.A类继承B类,A类中就直接拥有B类中的属性和方法。我们 就把A类叫B类的子类(派生类),把B类叫做A类的父类(基 类)。OC中的继承为单继承。
. 继承是一种关系:继承是类与类之间的关系,是一种“is a”关系。狗是动物 狗:动物
.方法的重写 : 如果重写父类的方法,优先调用子类的方法,如果子类没有 重写父类的方法,则调用父类的方法
.继承的优缺点
.提高了程序的复杂度,维护性和扩展性降低
.破坏类的封装性
.为什么使用继承
.代码复用
.制定规则
.为了多态
完整程序:
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=;
[animal eat]; TRDog* dog=[[TRDog alloc]init];
dog.age=;
[dog eat]; TRCat* dog=[[TRCat alloc]init];
[cat eat];
}
return ;
}
结果:
3岁的狗狗嗅一下
2岁的狗狗嗅一下
喵喵喵 .组合(一体机)
.表示两个对象之间是整体和部分的强关系,是“contains- a”关系
.部分的生命周期不能超越整体
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 ;
}
结果:
接通电源
cpu运行了
开始使用电脑 .聚合(台式机)
.表示两个对象之间是整体和部分的弱关系,是“has a”关系
. 部分的生命周期可以超越整体
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 ;
}
结果:
接通电源
cpu运行了
开始使用电脑 知识点
十七、多态 .多种形态,包括引用多态、方法多态。
a.引用多态
父类的引用可以指向本类对象
父类的引用也可以指向子类对象
b.方法多态 (如果引用指向子类对象)
如果子类重写了父类的方法,则优先调用子类的方法
如果子类没有重写父类的方法,则调用父类的方法
多态的引用只能调用父类的共享属性、方法,不能调用子类独有的方法
.好处:可以让我们设计更合理的代码,使用代码更通用,使用程序的
可维护性和可扩展性更强
例:
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 ;
} .多态可以用于数组
代码可以灵活处理一系列的数据
TRTransportation* trans[] = {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:];
//多态可以使用在数组中
//引用多态
TREmployee* emps[]={e1,e2,e3,e4};
for (int i=; i<; i++) {
[emps[i] show];//方法多态
} .多态可以用于方法的参数(最终的类)
方法可以灵活处理一系列的参数
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 ;
}
结果:
学生上学乘坐:
交通工具为自行车
.多态可以用于方法的返回值类型 (第二大类)
方法的返回值类型更加灵活,可以返回一系列对象
例:
其他文件内容不变,改以下:
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 ;
}
结果:
交通工具为的士 作业:
练习:重构
.写出以下类,用最少的代码解决问题。
TRShape形状类
|—————+—————|
TRRectangle矩形x,y TRCircle圆形r
|
TRSquare正方形x
求:周长perimeter与面积area,show方法查看周长和面积。(输出显示)
要使用属性、初始化方法、工厂方法、内存管理、继承。 .创建一个TREmployee类,TRStaff普通职员,TRManager领导,工资salary、工种job、姓名name,方法输出个人信息show方法,如果相应的工种领导的工资会比较普通职员高2000。TRHR类,人力资源,通过参数来招人,最少代码解决。(初始化方法、工厂方法、内存管理)
.软件工程师coder .测试工程师4500 .高级软件工程师8000
.软+领 .测+领 .高软+领
查看所有员工的信息?(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 :
return [[TRStaff alloc]initWithName:@"张三" andJob:@"软件工程师" andSalary:6000.0f];
break;
case :
return [[TRStaff alloc]initWithName:@"李四" andJob:@"测试工程师" andSalary:4500.0f];
break;
case :
return [[TRStaff alloc]initWithName:@"王五" andJob:@"高级软件工程师" andSalary:8000.0f];
break;
case :
return [[TRManager alloc]initWithName:@"赵六" andJob:@"软件工程师领导" andSalary:6000.0f];
break;
case :
return [[TRManager alloc]initWithName:@"钱七" andJob:@"测试工程师领导" andSalary:4500.0f];
break;
case :
return [[TRManager alloc]initWithName:@"黑八" andJob:@"高软件工程师领导" andSalary:8000.0f];
break;
default:
return nil;
break;
}
}
@end
main.m
@autoreleasepool {
TREmployee* emps[]; TREmployee* emp1 = [TRHr hrWithNum:];
TREmployee* emp2 = [TRHr hrWithNum:];
TREmployee* emp3 = [TRHr hrWithNum:];
emps[] = emp1;
emps[] = emp2;
emps[] = emp3; for (int i = ; i<; i++) {
[emps[i] print];
} } ./*创建一个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:];
//[a1 print];
TRArts *a2 = [TRPop popWithProduct:@"小苹果" andAuthor:@"筷子兄弟" andYear: andSinger:@"筷子兄弟" andTime:3.5f];
//[a2 print];
TRArts *a3 = [TRRock rockWithProduct:@"尽情摇摆" andAuthor:@"未知" andYear: andSinger:@"Beyond" andTime:4.5 andCount:];
//[a3 print];
TRArts* arts[] = {a1,a2,a3};
TRPerson *person = [[TRPerson alloc]init];
for (int i=; i<; i++) {
[person show:arts[i]];
} } 二、协议
xcode6
source->OC File->type(protocol)
.协议Protocol
协议指的是双方(苹果公司,程序员)的约定。
遵守一个约定,就等增强类的功能。 双方(程序员,程序员)
a.协议语法:
@protocol 协议名<父协议>
@required(默认)
必须遵守的属性或方法
drive;方法
@optional
可以遵守的属性或方法
@end
b.遵守协议
()类必须遵守协议
@interface 类名:父类名<协议>
()必须协议的方法
在.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 ;
}
结果:
实现了协议的方法 .协议与多态
.多态关注的是类的类型,
.而协议并不关注类的类型,关注的是类的方法和属性
.协议的继承
.协议的继承相当于协议的合并
.协议的引用只能调用协议中声明的方法或属性。
例:
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 ;
}
结果:
父协议中要求的方法
子协议中要求的方法
父协议中要求的方法
.多个协议
一个类可以遵守多个协议,也相当于协议的合并
@interface 类 :父类<协议1,协议2>
TRStudent.h遵守协议的时候
#import <Foundation/Foundation.h>
#import "TRTarena6.h"
#import "TRTarena2.h"
@interface TRStudent : NSObject<TRTarena2,TRTarena6>
.**协议中要求的属性,我们在遵守的时候要合成一下属性
.协议也可以与类定义在一个文件中(只需将协议中的内容复制到类的定义中)
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.分类:可以灵活的给指定的类添加能力,不需要修改源代码
一、分类 .语法规则:
分类文件命名: 主类类名+分类类名
#import "TRPerson+TRWeapon.h"
. *.h文件存放分类的声明部分内容
@interface 主类类名(分类类名)
//添加方法声明
@end
*.m文件存放分类的实现部分内容
@implementation 主类类名(分类类名)
//添加方法实现 @end
.在主函数中导入分类头文件, 主类对象既可以调用分类的方法
**注:.分类中是不可以声明实例变量的,自然也不可以创建属性
. 在分类中是可以访问主类的属性,也可以访问主类的实例变
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 = ;//分类中是可以访问主类的实例变量
self.i = ;//分类中是可以访问主类的属性
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 ;
}
具有工作的能力
具有了开火的能力
.给系统类添加分类
*分类不但可以给自己添加分类,还可以给系统添加分类。
可以给系统提供的类,如NSObject、NSString等,添加分类
NSString+TRFunction.h
如:NSString* n=[[NSString alloc]init];
[n function];
二、扩展
.扩展是一个特殊的分类。没有扩展名。
.保存的文件命名:
主类类名_扩展的文件名.h 只有.h文件
TRPerson_TRExtension.h
.***扩展只能在类的.m文件中使用
.可以给一个类添加私有的实例变量、方法、属性
例:
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 = ;
//self.i2 = 20;
NSLog(@"添加一个私有的方法。%d",self.i2);
} //类本身具有的方法
-(void)job{
//_i = 30;
self.i = ;
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 ;
}
结果:
具有工作的能力40
添加一个私有的方法。
• 分类与扩展的区别
- 分类:是不可以声明实例变量,通常是公开的,文件名通常 为:"主类类名+分类类名.h”
- 扩展:是可以声明实例变量,是私有的,文件名通常 为:“主类类名_扩展标识.h”,注意没有扩展名的 知识点
八、ARC内存管理
.强引用:(__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 (==) {
//默认就是强引用
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 ;
}
结果:
代码块末尾
学生具有学习的能力
学生对象销毁了
程序末尾 .弱引用:(__weak)仅仅的是指向对象,并不会通知引用计数器做加1或减1操作。而且不存在野指针问题,当对象不存在的时候,弱引用会自动置空。
**注意:创建对象时候,不可使用弱引用。
. _unsafe_unretain关键字
.@property(nonatomic,unsafe_unretained)int age;
.- unsafe_unretained等同于“assgin”,功能和__weak几乎 一样,唯一不同,没 有“zeroing weak reference”,通 常使用在基本数据类型
.ARC与MRC混编
()手动把MRC的代码转换成ARC的代码
retain=>strong release、autorelease、[super dealloc]删除掉
()自动将MRC转换成ARC的功能
.由 xcode帮我们删掉相应的方法:
菜单栏(Edit)->Refacotor(重构)->Convert to Objective-C ARC
恢复到MRC:File->Restore snapshot……
.通知编译器继续编译MRC代码:
项目栏->Build Phases->Compile Sources( item)->选择文件双击->- fno-objc-arc
恢复到MRC:-fobjc-arc
Objective-C汇总的更多相关文章
- Automake
Automake是用来根据Makefile.am生成Makefile.in的工具 标准Makefile目标 'make all' Build programs, libraries, document ...
- iOS常见面试题汇总
iOS常见面试题汇总 1. 什么是 ARC? (ARC 是为了解决什么问题而诞生的?) ARC 是 Automatic Reference Counting 的缩写, 即自动引用计数. 这是苹果在 i ...
- iOS 学习资料汇总
(适合初学者入门) 本文资料来源于GitHub 一.视频教程(英文) Developing iOS 7 Apps for iPhone and iPad斯坦福开放教程之一, 课程主要讲解了一些 iOS ...
- java相关网址汇总2
分享几个高质量的技术博客和网站. 一.博客 0.酷壳 - COOLSHELL 博客地址是 https://coolshell.cn/. 这个博客的作者是技术圈基本无人不知的技术大牛,江湖人称耗子叔,网 ...
- 常用 Gulp 插件汇总 —— 基于 Gulp 的前端集成解决方案(三)
前两篇文章讨论了 Gulp 的安装部署及基本概念,借助于 Gulp 强大的 插件生态 可以完成很多常见的和不常见的任务.本文主要汇总常用的 Gulp 插件及其基本使用,需要读者对 Gulp 有一个基本 ...
- 异常处理汇总 ~ 修正果带着你的Net飞奔吧!
经验库开源地址:https://github.com/dunitian/LoTDotNet 异常处理汇总-服 务 器 http://www.cnblogs.com/dunitian/p/4522983 ...
- UWP开发必备:常用数据列表控件汇总比较
今天是想通过实例将UWP开发常用的数据列表做汇总比较,作为以后项目开发参考.UWP开发必备知识点总结请参照[UWP开发必备以及常用知识点总结]. 本次主要讨论以下控件: GridView:用于显示数据 ...
- Oracle手边常用70则脚本知识汇总
Oracle手边常用70则脚本知识汇总 作者:白宁超 时间:2016年3月4日13:58:36 摘要: 日常使用oracle数据库过程中,常用脚本命令莫不是用户和密码.表空间.多表联合.执行语句等常规 ...
- Oracle 数据库知识汇总篇
Oracle 数据库知识汇总篇(更新中..) 1.安装部署篇 2.管理维护篇 3.数据迁移篇 4.故障处理篇 5.性能调优篇 6.SQL PL/SQL篇 7.考试认证篇 8.原理体系篇 9.架构设计篇 ...
- Vertica 数据库知识汇总篇
Vertica 数据库知识汇总篇(更新中..) 1.Vertica 集群软件部署,各节点硬件性能测试 2.Vertica 创建数据库,创建业务用户测试 3.Vertica 数据库参数调整,资源池分配 ...
随机推荐
- canvas学习笔记:canvas对图片的像素级处理--ImageData的应用
学习了canvas的基本绘图功能后,惊喜的发现canvas对图片数据也有相当强大的处理功能,能够从像素级别操作位图,当然[lte ie8]不支持. 主要的函数有三个: ctx.createImageD ...
- CASS 2008的野外操作码
表D-1 线面状地物符号代码表 坎类(曲): K(U) + 数(0-陡坎,1-加固陡坎,2-斜坡,3-加固斜坡,4-垄,5-陡崖,6-干沟) 线类(曲): X(Q) + 数(0-实线,1-内 ...
- 利用WPS 2012/2013 0day针对中国政府部门的定向攻击
今天早上,我们捕获到一个利用wps 2012/2013 0day针对中国政府部门的钓鱼邮件定向攻击事件. 邮件发件人以2014中国经济形势解析高层报告组委会 标题发出,附件为包含wps2012 0da ...
- Java中将一个字符串传入数组的几种方法
String Str="abnckdjgdag"; char a[]=new char[Str.length()]; -------------------方法1 用于取出字符串的 ...
- M1/M2个人总结
软件工程整个学期结束了,很开心学了这门课,在学到知识的同时也提高了自己的动手实践的能力,感觉自己在整个软件工程的各个环节中都能有所把握,可以将学到的知识运用到设计.实践更多的项目中去. M1阶段个人总 ...
- Apache php Mysql部署(一)下载安装
前言 最近公司需要开发一个网站,但是又有特殊要求:不能使用java.只能在Windows平台部署.没方法,只能选择了Apache+php+Mysql的方案. 不知道有没有更好的,听所golang挺不错 ...
- 将命令添加到shell脚本中然后设置开机自启动
例如开机自启动nginx 编写一个脚本 #vi /usr/local/Monitor_nginx.sh #!/bin/bash if [ "$(ps -ef | grep "ngi ...
- Win Form程序线程点点
消息循环 Win32窗体程序基于消息驱动的,程序的模型就是一个用户触发事件消息->系统分发事件消息->程序处理事件的循环过程. .NET Win Form程序对消息循环进行了封装,可以看到 ...
- zip压缩命令的使用
file命令可以查看文件的类型 tar类型 .tar gzip类型 .gz bzip2类型 .bz2 zip类型 .zip 如果一个压缩文件由tar命令解压的前提,2个条件 1.这个文件 ...
- 麦咖啡阻挡正常打开Excel文件
双击打开Excel文件,提示如下图: Excel文件被麦咖啡做阻挡,无法正常打开 处理方案: 过一会儿还是出现此问题,干脆就把缓冲区保护给禁用掉