OC_11_1类目与延展

本节咱们来说说类目、延展、协议(协议将在_2中讲)。进入正题,咱们先建立以下工程:
这里写图片描述
先将工程建好,依然是建立IOS—Single View Application–这里就不多讲了。然后进去之后,建立一个Tool工具和MyClass类,都继承于NSObject。
♢建立类目延展的简单步骤:
command+N—-iOS—–Source—Objective-C File–next—
File:<填你的类目或延展名>—在我这儿我把它名为:
MyClass_Extension/Tool_Category/NSObject_Category
File Type:<填的就是你想建立的文件类型>
Empty File—空白文件
Category—类目
Protocol—协议
Extension—延展
Class:<你要为哪一个类建立类目、延展、协议…>
我为MyClass建立一个延展,为Tool建立一个类目,为NSObject也建立一个类目,这其中有一个概念,就是 :
NSObject的类目声明就称为非正式协议。
创建一个NSObject的类目而不实现称为“创建一个非正式协议”。
创建好工程,我先跟大家说下到底什么是类目和延展呢?
类目:
定义:为现有工程中的类和系统类添加新的方法
作用:在类目中添加新的方法及属性和在原类中添加方法和属性是一样的,都能够被类和该类的子类调用,这样可以快速便利维护和开发项目。
延展很简单
延展的作用就是定义自己的私有方法
先来举个例子演示一下:
咱们去到Tool.h文件,给它一个名字,一个名为property1的属性和一个function1方法:

 @interface Tool : NSObject
{
    NSString *_name;
}
@property (nonatomic,strong)NSString *property1;
-(void)function1; //原始类的方法

@end

既然创建了类目,我们就在Tool.h接着上面继续往下,咱们来用一下:

#pragma mark ---类目---
//在类目中为原类添加新的方法和属性
/*
 ✪类目的使用场景
 1.类包含了很多个方法实现,而这些方法需要不同团队成员来实现
 2.当你在使用基础类库中的类时,你不想继承这些类而指向添加一些方法时
 //比如 NSObject没有你所需要的功能,就可以添加个类目,类目中就可以写你需要的方法,注意,不要被误导了,

 ✪使用类目的时候需要注意的问题
 ①类目可以访问原始类的实例变量。但不能添加实例变量,如果想添加实例变量,那就通过继承创建子类来实现
 ②类目可以重载原始类的方法,但不推荐这么做,这样会覆盖掉原始类的方法。如果确实要重载,那就通过继承创建子类来实现
 ③和普通接口有所区别的是,在类目的实现文件中的实例方法只要你不去调用它你可以不要实现所有声明的所有方法。

 */
@interface Tool (ToolCategory)
//{
//    NSString *_property2; //这样做是会报错的,因为类目中不能添加实例变量
//}
/*
 ios运行时机制
 ios运行时机制,简单来说,就是苹果为开发者提供的一套运行时动态创建类、方法、属性的API,它是一套纯C语言的API。

 */
@property (nonatomic ,strong)NSString *property2;

-(void)function2;
//-(void)function1;  //并不建议这么做
@end
因为涉及到ios运行时机制,咱们在Tool.m文件中就导入了相关的一个头文件 <objc/runtime.h>,网上说:

特别注意的是,如果是需要上架的APP,切勿使用私有API,会通不过APP Store的审核。

我们来看看Tool.m 的代码:

#import "Tool.h"
#import "objc/runtime.h"

@interface Tool ()


@end

@implementation Tool

-(void)function1{

    NSLog(@"I am function1");
}

@end

@implementation Tool (ToolCategory)


-(void)function2{
    NSLog(@"%@",_name);  //表示可以访问原类的实例变量
    NSLog(@"I am function2");
    NSLog(@"%@",self.property2); //输出property2

}

//-(void)function1{                   //输出结果覆盖原来的“I am function1”
//    NSLog(@"我是类目中的Function1");  //这么做会出现警告,而警告就是建议我们直接写到tool类中即可
//}
#pragma mark --合成类目中的属性---
-(void)setProperty2:(NSString *)property2{
    //_property2 = property2;
    /*
     id object:给哪个对象的属性赋值
     const void *key:属性对应的key
     id value:设置属性值为value
     <#objc_AssociationPolicy policy#>:使用的策略
     */
    objc_setAssociatedObject(self, @selector(property2), property2, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSString *)property2{
    return objc_getAssociatedObject(self, @selector(property2));
}
@end

代码片中提到了 合成类目中的属性,用的就是之前学过的设置器和访问器。
当然,既然建了类目,咱们就给类目写个方法,去到Tool+Tool_Category.h文件:

-(void)function3;

给它一个function3的方法,然后去.m文件实现一下:

-(void)function3{
    NSLog(@"I am function3");
}

再回到ViewController.m函数中:

Tool *tool = [Tool new];//创建一个Tool对象
[tool function1]; //调用function1方法

    [tool setValue:@"My name is Jason" forKey:@"_name"];//利用KVC给tool对象赋值
    tool.property2 = @"property2"; //给property2赋值
    [tool function2]; //调用function2
    //    [tool function3];

咱们运行一下,看到结果是:
这里写图片描述
接下来,咱来举个例子讲讲延展,去到MyClass_MyClass_Extension.h文件:
给它一个方法:-(void)testExtension2;
我们去MyClass.m中实现一下:
首先是导入延展的一个头文件,然后:

@interface MyClass ()
-(void)testExtension;
@end
@implementation MyClass
-(void)testExtension{

    NSLog(@"我是延展 testExtension");
}
-(void)testExtension2{ //再另外加多个延展2
    NSLog(@"我是延展 testExtension2");
}
@end

由于延展调用的私有方法是不能进行调用的,所以只能依赖别的方法来进行输出,去到NSObject+NSObject_Category.h文件,给它写两个方法,方便调用:

#import <Foundation/Foundation.h>
@interface NSObject (NSObject_Category)
-(void)test1;
-(void)test2;
@end

然后回到MyClass.m文件中,咱们调用一下这两个方法:

@implementation MyClass
-(void)test1{

    NSLog(@"I am test1");
}
-(void)test2{
    NSLog(@"I am test2");
    [self testExtension];
    [self testExtension2];//私有方法不能调用,所以在这里进行输出
}

-(void)testExtension{

    NSLog(@"我是延展 testExtension");
}

-(void)testExtension2{
    NSLog(@"我是延展 testExtension2");
}
@end

然后,再次回到ViewController.m:

MyClass *myclass = [[MyClass alloc]init];

    //respondsToSelector:(SEL)aSelector 这个方法可以检查当前对象是否响应aSelector方法
    if ([myclass respondsToSelector:@selector(test1)]) {
        [myclass test1];
    }
    if ([myclass respondsToSelector:@selector(test2)]) {
        [myclass test2];
    }

-(BOOL)respondsToSelector:(SEL)aSelector;
判断receiver是否响应某消息,注意:不包括类方法。

最后咱们来看下运行结果:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值