黑马程序员_分类协议代码块

---------------------- ASP.Net+Unity开发 .Net培训 、期待与您交流!----------------------

分类

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培训、期待与您交流!----------------------


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值