======文档更新状态=====
2015-12-18:发布
==================
day06-2015-12-17
一、属性
1.简单的封装技术,可以自动生成相应代码
2.语法:声明(接口)部分使用@property;
实现部分使用@synthesize(OC1.0是必须要写的,OC2.0基本都省略不写)
3.当使用对象指针指向对象实例时,可以使用.运算符访问getter和setter;而id类型不可以,只能通过方法调用
4.如果要对数据进行有效性处理,则需要在实现部分重写setter
5.如果想设为只读,则需在@property后面增加一对小括号,在小括号里增加修饰符:readonly (默认:readwrite)
关于修饰符:
A.readonly和readwrite
B.atomic和nonatomic
一般单线程程序使用nonatomic,多线程使用atomic
C.setter和getter:重新定义属性对应得get方法和set方法名;一般BOOL类型的属性需要重新定义getter;注意setter方法名必须以:结尾
D.assign,retain,copy
E.strong,weak,unsafe_unretained
一些通俗解释
属性
1.一种简化的封装技术
2.语法:在@interface中使用@property指令声明即可,老版本(iOS6之前)还需要在@implementation中使用@synthesize生成,默认情况下使用@synthesize生成的成员变量与属性同名,而不使用@synthesize时,成员变量名以下划线开头
3.使用:既可以使用简化的.运算符,也可以使用方法访问
4.默认情况下getter和setter按照属性名生成,getter与属性名相同,setter在属性名前加set并改属性名首字母大写;除了BOOL类型需要指定getter外,一般不建议修改默认的getter和setter
5.如果指定了属性的getter和setter,则对使用方法访问属性造成影响,但对.运算符没有任何影响
6.readonly(只读,不产生setter,一般由init家族方法进行赋值)和readwrite(读写,默认)
7.atomic和nonatomic:多线程程序中需要在数据安全性和性能之间平衡,单线程中只要考虑性能即可
8.内存管理相关(ARC:Automatic Reference Counting,和MRC对应)
A.assign:基本类型固定使用,对象指针也可以,但对RC无影响
B.retain:对象指针使用,对RC有影响
C.copy:对象指针使用,遵循NSCopying协议的对象才可以使用
D.weak(仅用于ARC)
E.strong(仅用于ARC)
F.unsafe_unretained(仅用于ARC)
// 注意下面.h文件中属性的写法
// YYPerson.h
#import <Foundation/Foundation.h>
@interface YYPerson : NSObject
@property (nonatomic,assign) int age;//属性
@property (getter=isMarried,assign) BOOL married;
@property (readonly) NSString* name;
-(instancetype)initWithName:(NSString*)name age:(int)age;
@end
// YYPerson.m
/
//
#import "YYPerson.h"
@implementation YYPerson
//@synthesize age=_age;//age
-(NSString *)description{
return [NSString stringWithFormat:@"person %@'s age is %d",_name,_age];
}
-(void)setAge:(int)age{
if (age<0 || age>150) {
_age=10;
}
else{
_age=age;
}
}
-(instancetype)initWithName:(NSString *)name age:(int)age{
if (self=[super init]) {
self->_name=[name copy];
self.age=age;
}
return self;
}
@end
// main.m
#import "YYPerson.h"
int main_property(int argc, const char * argv[]) {
YYPerson* p1=[YYPerson new];
p1.age=-100;
NSLog(@"age:%d",p1.age);//10
p1.married=YES;
NSLog(@"married:%d",p1.married);
NSLog(@"married:%d",[p1 isMarried]);
NSLog(@"---------------");
YYPerson* p2=[[YYPerson alloc]initWithName:@"mike" age:200];
NSLog(@"p2:%@",p2);
return 0;
}
二、协议protocol
1.仅有方法声明,没有方法实现,也没有成员变量和属性
2.可以实现“多继承”结构
3.语法:
A.定义协议
@protocol 协议名 <父协议>
//方法声明
@end
B.遵循协议
@interface 子类名:父类<协议名>
//子类自己新增的成员变量、属性、方法等
@end
C.创建对象
使用对象指针加协议名(可以访问指针类型中的方法以及协议中的方法)或id加协议名(只能访问协议中的方法)
一些通俗解释
协议@protocol
1.协议只是方法规范,无实现,一个类可以遵循多个协议,但要给出每个协议中声明的方法的实现
2.语法:
@protocol 协议名 [<父协议,…>]
//方法声明
@end
3.使用
A.子类遵循:
@interface 子类名:父类名<父协议名>
//自己的成员变量、属性、方法等声明
@end
B.对象创建
a).使用本类指针指向本类对象,所有父类、自身类以及协议中的方法、属性都可以
b).使用父类指针指向子类对象,只能访问所有父类的方法、属性
c).使用父类指针加协议名指向子类对象,所有父类以及协议中的方法、属性都可以
d).使用id类型,当前环境下所有能够访问到的方法,但是不保证能够执行成功
e).使用id类型加协议名,只能访问协议中的方法
C.多个协议:基本概念与单协议相同,需要访问哪些协议中的方法,就在父类指针或id后面加上相应的协议名,可以加多个
4.协议继承,可以多继承,但最好还是要符合is a关系
5.关于必须@required和可选@optional:必须和可选的区别仅仅是在子类中如果没有实现是否给出警告信息(必须的有警告,可选的没有),如果未实现时去访问能够通过编译,但运行时还是会出错
// protocol的关于对象创建的例子
// YYFighting.h
#import <Foundation/Foundation.h>
@protocol YYFighting <NSObject>
-(void)fight;
@end
// YYPerson.h
#import <Foundation/Foundation.h>
@interface YYPerson : NSObject
@property (nonatomic,assign) int age;//属性
@property (getter=isMarried,assign) BOOL married;
@property (readonly) NSString* name;
-(instancetype)initWithName:(NSString*)name age:(int)age;
@end
// YYPerson.m
#import "YYPerson.h"
@implementation YYPerson
//@synthesize age=_age;//age
-(NSString *)description{
return [NSString stringWithFormat:@"person %@'s age is %d",_name,_age];
}
-(void)setAge:(int)age{
if (age<0 || age>150) {
_age=10;
}
else{
_age=age;
}
}
-(instancetype)initWithName:(NSString *)name age:(int)age{
if (self=[super init]) {
self->_name=[name copy];
self.age=age;
}
return self;
}
@end
// YYSoldier.h
#import "YYPerson.h"
#import "YYFighting.h"
@interface YYSoldier : YYPerson<YYFighting>
@property (nonatomic,assign)int level;
@end
#import "YYSoldier.h"
@implementation YYSoldier
-(void)fight{
NSLog(@"%@ is fighting.",self.name);
}
@end
#import "YYSoldier.h"
int main_protocol1(){
//使用本类指针指向本类对象
YYSoldier* s1=[[YYSoldier alloc]initWithName:@"mike" age:33];
[s1 fight];//协议的
[s1 setAge:10];//父类的
[s1 setLevel:100];//自己的
//使用父类指针指向子类对象
YYPerson* p1=[[YYSoldier alloc]initWithName:@"jerry" age:22];
[p1 setAge:20];//父类的
// [p1 fight];
// [p1 setLevel:100];
//使用父类指针加协议名指向子类对象
YYPerson<YYFighting>* p2=[[YYSoldier alloc]initWithName:@"andy" age:26];
[p2 setAge:20];//父类的
[p2 fight];//协议的
// [p2 setLevel:100];
//使用id类型
id t1=[[YYSoldier alloc]initWithName:@"tom" age:36];
[t1 setAge:10];
[t1 setLevel:2000];
[t1 fight];
// [t1 stringByAppendingString:@"fff"];//能通过编译,运行出错
id<YYFighting> t2=[[YYSoldier alloc]initWithName:@"marry" age:31];
[t2 fight];
[t2 description];
NSObject<YYFighting>* t3;
[t3 description];
return 0;
}
关于protocol的重点强调
对象创建
a).使用本类指针指向本类对象,所有父类、自身类以及协议中的方法、属性都可以
b).使用父类指针指向子类对象,只能访问所有父类的方法、属性
c).使用父类指针加协议名指向子类对象,所有父类以及协议中的方法、属性都可以
d).使用id类型,当前环境下所有能够访问到的方法,但是不保证能够执行成功
e).使用id类型加协议名,只能访问协议中的方法
C.多个协议:基本概念与单协议相同,需要访问哪些协议中的方法,就在父类指针或id后面加上相应的协议名,可以加多个
三、代理协议
1.目标:自己类不去完成、实现具体操作,而是交给别的类的对象(即:代理)去做
2.思路:
A.定义一个代理协议,规定好代理应该具有的功能(即:方法声明)
B.定义一个主类,包含一个代理属性以及若干功能,其中某些功能在实现时,直接交给代理属性去做,而不自己实现
C.创建若干遵循代理协议的子类,分别实现代理协议中规定的方法
D.在创建主类对象后,调用应该由代理去做的方法前,给代理属性赋上一个代理子类的对象
一些通俗解释
设计模式:代理delegate
1.自己不做,交给代理做(如果有代理,交给代理做;如果没有代理就自己做)
2.实现步骤
A。定义一个协议,规定一些代理所必须遵守的规范(方法)
B。再定义若干代理子类,遵循该协议,并给出方法的实现
C。在主类中定义一个协议类型的成员变量或属性
D。在主类中声明一些方法,在实现时调用遵循了代理协议的子类对象的方法,而不是自己去做具体事情
3.注意事项:任何由nil访问的方法都不会执行,如:NSObject* obj=nil;
[obj buy];//不执行
如果方法有返回值类型,则一律以各种0表示
// 代理模式的一个例子
// YYManager.h
// 主类:需要用到代理的类
//
//
#import "YYAssistant.h"
@interface YYManager : NSObject
@property (nonatomic,weak) id<YYAssistant> delegate;
-(void)write;
-(void)buy;
-(void)say;
-(int)eat;
@end
// YYManager.m
#import "YYManager.h"
@implementation YYManager
-(void)buy{
// 如果有代理就让代理做,如果没有代理就自己做
if (_delegate!=nil) {
//如果_delegate不为nil时,交给代理执行
[_delegate buyTicket:@"NJ" to:@"BJ"];
}
else {
NSLog(@"经理自己买机票。");
}
}
-(void)write{
if (_delegate!=nil){
[_delegate writeDoc];
}
else{
NSLog(@"经理自己写文章。");
}
}
-(void)say{
NSLog(@"经理说话");
}
-(int)eat{
return 100;
}
@end
// YYAssistant.h
// 代理协议:定义一个助理所需要完成的事情
// 1.写文章
// 2.买机票
//
//
#import <Foundation/Foundation.h>
@protocol YYAssistant <NSObject>
-(void)writeDoc;
-(void)buyTicket:(NSString*)from to:(NSString*)to;
@end
// YYGoodAssistant.h
#import "YYAssistant.h"
@interface YYGoodAssistant : NSObject<YYAssistant>
@end
// YYGoodAssistant.m
#import "YYGoodAssistant.h"
@implementation YYGoodAssistant
-(void)writeDoc{
NSLog(@"写了一篇流芳百世的文章!");
}
-(void)buyTicket:(NSString *)from to:(NSString *)to{
NSLog(@"买了一张从%@到%@的机票。",from,to);
}
@end
// YYFoolAssistant.h
#import "YYAssistant.h"
@interface YYFoolAssistant : NSObject<YYAssistant>
@end
// YYFoolAssistant.m
#import "YYFoolAssistant.h"
@implementation YYFoolAssistant
-(void)writeDoc{
NSLog(@"写了一篇遗臭万年的文章!");
}
-(void)buyTicket:(NSString *)from to:(NSString *)to{
NSLog(@"买了一张从%@到%@的机票。",to,from);
}
@end
// test_delegate.m
/
#import "YYManager.h"
#import "YYGoodAssistant.h"
#import "YYFoolAssistant.h"
int main(){
YYManager* ma=[YYManager new];
// YYGoodAssistant* ga=[YYGoodAssistant new];
// YYFoolAssistant* ga=[YYFoolAssistant new];
// ma.delegate=ga;
[ma buy];
[ma write];
return 0;
}
关于代理的一些总结:
1>实现步骤
A。定义一个协议,规定一些代理所必须遵守的规范(方法)
B。再定义若干代理子类,遵循该协议,并给出方法的实现
C。在主类中定义一个协议类型的成员变量或属性
D。在主类中声明一些方法,在实现时调用遵循了代理协议的子类对象的方法,而不是自己去做具体事情
2>@property (nonatomic,weak) id<YYAssistant> delegate;
这里的id<YYAssitant>表示当前对象不知道他的代理的类型只是知道
它的代理必须遵循YYAssistant协议
3>注意体会代理设计模式思想
5> IOS中是这样使用代理的:
如果有代理就让代理做,否则就自己做