分类
1.category的声明
category即分类,也有叫类别,类目。分类为类的拓展提供了另一种方法。分类可以在不改变原有类的基础上,增加类的方法或者覆写已有类的方法。
Seed.h
@interface Seed : NSObject
@property int count;
@property NSString *name;
- (void)print;
@end
Seed.m
@implementation Seed
- (void)print
{
NSLog(@"count = %d",_count);
NSLog(@"name = %@",_name);
}
@end
Seed+fruite.h
@interface Seed (fruite)
- (void)print;
- (void)fun;
@end
Seed+fruite.m
@implementation Seed (fruite)
- (void)print
{
NSLog(@"fruite is loading");
}
- (void)fun
{
NSLog(@"fruite is fun");
}
@end
main.m
int main(int argc, const char * argv[])
{
Seed *s = [Seed new];
[s print];
[s fun];
return 0;
}
运行结果:
2014-06-05 18:07:43.035 cate[1306:303] fruite is loading
2014-06-05 18:07:43.037 cate[1306:303] fruite is fun
Program ended with exit code: 0
OC中不提倡用分类覆写原有类的方法,所以在编译的时候会有警告,但是不影响程序的运行。分类一般拓充原有类中没有的方法。
2.分类的拓充方法
OC在使用分类扩充方法时,如果有原有类中没有的方法,分类不改变原有类编译运行。如果分类中覆写了原有类中的方法,分类会替代该类中的方法。如果子类的分类覆写了父类中的方法,那么父类的方法就不能使用。
Person.h
@interface Person : NSObject
{
int _num;
NSString *_name;
}
@property int num;
@property NSString *name;
- (void)test;
- (void)study;
@end
Person.m
@implementation Person
- (void)test
{
NSLog(@"Person is test");
}
- (void)study
{
NSLog(@"Person is study");
}
@end
Student.h
@interface Student : Person
@end
Student.m
@implementation Student
- (void)test
{
NSLog(@"Student is test");
}
@end
Person+test.h
@interface Person (test)
- (void)print;
@end
Person+test.m
@implementation Person (test)
- (void)print
{
NSLog(@"num = %d",_num);
NSLog(@"name = %@",_name);
}
@end
Student+study.h
@interface Student (study)
@end
Student+study.m
@implementation Student (study)
- (void)study
{
NSLog(@"Student+study is study");
}
- (void)test
{
NSLog(@"Student+study is test");
}
@end
Student+test.h
@interface Student (test)
- (void)test;
- (void)study;
- (void)print;
@end
Student+test.m
@implementation Student (test)
- (void)test
{
NSLog(@"Student+test is test");
}
- (void)study
{
NSLog(@"Student+study is study");
}
- (void)print
{
NSLog(@"name = %@",_name);
NSLog(@"num = %d",_num);
}
@end
main.m
int main(int argc, const char * argv[])
{
Person *p = [[Person alloc] init];
[p test];
[p study];
p.name = @"lsmseed";
p.num = 10;
[p print];
Student *s = [[Student alloc] init];
[s test];
[s study];
[s print];
s.name = @"buster";
s.num = 20;
[s print];
return 0;
}
运行结果:
2014-06-05 18:42:59.330 rer[1552:303] Person is test
2014-06-05 18:42:59.335 rer[1552:303] Person is study
2014-06-05 18:42:59.337 rer[1552:303] num = 10
2014-06-05 18:42:59.338 rer[1552:303] name = lsmseed
2014-06-05 18:42:59.339 rer[1552:303] Student+test is test
2014-06-05 18:42:59.340 rer[1552:303] Student+study is study
2014-06-05 18:42:59.341 rer[1552:303] name = (null)
2014-06-05 18:42:59.343 rer[1552:303] num = 0
2014-06-05 18:42:59.345 rer[1552:303] name = buster
2014-06-05 18:42:59.346 rer[1552:303] num = 20
Program ended with exit code: 0
由于分类覆写了原有类中的方法,因此,类在调用方法时优先会在分类中寻找对应的方法,如果没有会依次在子类,在父类中找到对应的方法。如果分类较多,最后编译的分类方法优先级高。同时,分类还可以访问原有类中的成员变量。
3.分类的使用注意
- 分类不提倡覆写原有类中的同名方法
- 分类不能增加原有类中的成员变量
- 分类方法的调用优先级是参与编译的顺序:最后编译的优先调用。
协议
1.协议的声明格式
OC中的协议类似java中的接口,只不过OC中的协议只有方法的声明,不能定义变量。一般协议的声明方式如下:
@protocol Myprotocol <NSObject>
- (void)fun;
@required
- (void)print;
@optional
- (void)test;
- (void)test2;
@end
@protocol是声明协议的关键字,Myprotocol是协议名称。一般协议中声明的方法默认都是必须实现的,也就是@required修饰的方法声明。@optional是可选实现的方法。虽然@required是必须实现的方法,但是即便没有实现编译器也不会报错,只会报警告。
2.基协议
基协议就是最基本的协议,也就是NSObject协议。这个协议中声明了许多OC框架中基本的方法。一般在新定义的协议中都会遵守基协议。
@protocol Myprotocol <NSObject>
3.协议限制对象
在创建对象时,可以指定对象需要遵守的协议。这样协议就规定了创建出的对象必须实现的方法。
Myprotocol.h
@protocol Myprotocol <NSObject>
@required
- (void)print;
- (void)fun;
@end
Car.h
#import "Myprotocol.h"
@interface Car : NSObject<Myprotocol>
@end
Car.m
@implementation Car
- (void)print
{
NSLog(@"seed");
}
- (void)fun
{
NSLog(@"fun");
}
@end
Red.h
@interface Red : NSObject
@end
Red.m
@implementation Red
- (void)print
{
NSLog(@"Red is print");
}
- (void)fun
{
NSLog(@"Red is fun");
}
- (void)test
{
NSLog(@"red is test");
}
- (void)test1
{
NSLog(@"red is test1");
}
@end
main.m
#import "Myprotocol.h"
#import "Car.h"
#import "Red.h"
int main(int argc, const char * argv[])
{
NSObject<Myprotocol> *obj = [[Car alloc] init];
[obj print];
[obj fun];
NSObject<Myprotocol> *obj1 = [[Red alloc] init];
[obj1 print];
return 0;
}
运行结果:
2014-06-06 18:25:04.959 dd[1080:303] seed
2014-06-06 18:25:04.962 dd[1080:303] fun
2014-06-06 18:25:04.963 dd[1080:303] Red is print
Program ended with exit code: 0
定义一个限定遵守制定协议的对象,其对象本身就是一个已遵守该协议的一个引用。只要创建一个已经遵守这个协议的对象并赋值就可以了。虽然也可以传入未实现该协议且已实现该协议方法的对象,但是,编译时会出警告。协议限定对象也可以限定类中的成员。
Study.h
@protocol Study <NSObject>
- (void)work;
- (void)hard;
@end
Work.h
@protocol Work <NSObject>
- (void)work1;
@end
Person.h
#import "Work.h"
@interface Person : NSObject<Work>
@property int num;
@property NSString *name;
- (void)work1;
@end
Person.m
@implementation Person
- (void)work1
{
NSLog(@"Person is work1");
}
@end
Student.h
#import "Study.h"
@interface Student : Person<Study>
- (void)hard;
- (void)work;
@end
Student.m
@implementation Student
- (void)hard
{
NSLog(@"Student is hard");
}
- (void)work
{
NSLog(@"Student is work");
}
@end
School.h
#import "Study.h"
#import "Student.h"
#import "Person.h"
#import "work.h"
@interface School : NSObject
@property (nonatomic,strong) Student<Study> *s;
@property (nonatomic,strong) id<Work> p;
@end
School.m
@implementation School
@end
main.m
#import "School.h"
int main(int argc, const char * argv[])
{
School *sc = [[School alloc] init];
sc.s = [[Student alloc] init];
sc.p = [[Person alloc] init];
[sc.s hard];
[sc.p work1];
return 0;
}
运行结果:
2014-06-06 18:54:56.628 sd[1243:303] Student is hard
2014-06-06 18:54:56.634 sd[1243:303] Person is work1
Program ended with exit code: 0
使用property修饰的成员也可以被协议限定,这样自动生成的方法,也要接受遵守协议地对象作为成员。
4.协议提前声明
为了提高编译效率,有时在遵守协议地类中可以不用先导入协议地头文件,可以使用@protocol来先声明要遵守地协议。
@protocol Study;
@interface Student : Person<Study>
- (void)hard;
- (void)work;
@end
如果要实现协议的方法那就要在实现的文件中导入头文件。
#import "Study.h"
@implementation Student
- (void)hard
{
NSLog(@"Student is hard");
}
- (void)work
{
NSLog(@"Student is work");
}
@end
5.协议遵守协议
声明一个协议后还可以让这个协议继续遵守另一个协议,这样这个协议的方法就被进一步扩充一次。
@protocol Work;
@protocol Study <Work>
- (void)work;
- (void)hard;
@end
一个协议遵守另一个协议,这样该协议就拥有了另一个协议的方法声明。在方法拓展上,可以将一个大家普遍使用的协议做成基本协议,然后再衍生出一些子协议。
6.代理模式
代理模式是一种程序的设计模式,简单来说代理就是找人帮忙做自己不能直接完成的事。有了代理,一切事务都可以交给他来完成,不用自己亲自动手。
Dele.h
@protocol Dele <NSObject>
- (void)catch;
- (void)throw;
@end
Person.h
@class Dog;
@protocol Dele;
@interface Person : NSObject
@property NSString *name;
@property (nonatomic,strong) Dog<Dele> *d;
- (void)test;
@end
Person.m
#import "Dog.h"
#import "Dele.h"
@implementation Person
- (void)test
{
[_d catch];
[_d throw];
}
@end
Dog.h
@protocol Dele;
@interface Dog : NSObject <Dele>
@end
Dog.m
#import "Dele.h"
@implementation Dog
- (void)catch
{
NSLog(@"Dog is catch");
}
- (void)throw
{
NSLog(@"Dog is throw");
}
@end
main.m
#import "Dele.h"
#import "Person.h"
#import "Dog.h"
int main(int argc, const char * argv[])
{
Person *p = [[Person alloc] init];
p.d = [[Dog alloc] init];
[p test];
return 0;
}
运行结果:
2014-06-07 09:09:00.007 dele[445:303] Dog is catch
2014-06-07 09:09:00.010 dele[445:303] Dog is throw
Program ended with exit code: 0
创建一个Person对象,再在对象中创建一个代理属性,这个属性接收一个遵守协议的对象后就可以代替类拓充一些方法。Person对象中拥有d属性且d属性遵守Dele协议,这样d属性就必须有Dele中的方法实现。因此,Person中的test方法,是由代理d间接实现的。
block
1.block的定义
OC中的block和C中的函数很像,都能封装一段具有特定功能的一段代码。但是,block的定义和使用比函数更加灵活。block在程序中定义的位置较灵活,OC建议多用block。
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
void (^myblock)() = ^{
NSLog(@"seed");
};
myblock();
int (^sum)(int,int);
sum = ^(int a,int b){
return a + b;
};
NSLog(@"sum = %d",sum(10,20));
typedef NSString *(^print)(NSString *);
print lsm;
lsm = ^(NSString *name){
return name;
};
NSLog(@"%@",lsm(@"lsmseed"));
return 0;
}
运行结果:
2014-06-07 09:53:55.881 b1[608:303] seed
2014-06-07 09:53:55.894 b1[608:303] sum = 30
2014-06-07 09:53:55.896 b1[608:303] lsmseed
Program ended with exit code: 0
block的定义特点就是在block名称前加^号。block的定义可以带参数也可以不带参数。不带参数的定义在给block赋值时一定要保留小口号,也就是void (^block)(),否则编译报错。带参的block要注意block默认的返回值是int型。
2.block的应用
block的应用主要是在IOS开发中的GCD中,它可以方便系统的接口调用。就block本身来说它和函数指针几乎一模一样。但是函数需要先定义再使用,而block可以直接调用代码块使用。
3.block变量值的修改
block内部可以访问外部的变量,但是不能修改外部变量。如果想修改block外部的变量要加关键字_block。
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
__block int a = 10;
void (^myblock)() = ^{
NSLog(@"a = %d",a);
a += 10;
NSLog(@"a = %d",a);
};
myblock(a);
return 0;
}
运行结果:
2014-06-07 10:25:06.385 b1[645:303] a = 10
2014-06-07 10:25:06.388 b1[645:303] a = 20
Program ended with exit code: 0
----------------------ASP.Net+Unity开发、.Net培训、期待与您交流!----------------------