扩展问题

今天主要为NSString类扩展一个类方法


为了在此blog简化讲解过程,类方法名称=PrintToConsole,此方法在此仅仅是模拟函数


在实践中,遇到两个问题。


分别描述实践过程。


1、新建文件ExtString.h,ExtString.m
@interface NSString(ExtString)


+(void) PrintToConsole:(NSString *)plainText;


@end


实现:
+(void) PrintToConsole:(NSString *)plainText
{
    NSLog(@"%@" ,plainText);
}


2、新建一个项目TestA,添加上述文件
在main函数中,添加此头文件,
NSString *test = @"The boy is good";
[NSString PrintToConsole:test];


此项目TestA运行正常,输出The boy is good。


3、新建静态库libUtils,添加ExtString两个文件
编译通过


4、新建一个项目TestB,在Build设置中添加静态库libUtils
同样在main中添加同样的测试代码


现在出现了错误:unrecognized selector sent to XXXXXX


分析:TestA运行正常,TestB出现异常,说明要么TestB没有找到静态库,要么静态库的配置和输出不正确
按项目的文件存在来看,TestB应该找到静态库


由于对扩展方法的使用经验不足,我先建议使用普通类的方式先实现


5、在libUtils,新建两个文件ConsoleObj.h,ConsoleObj.m
@interface ConsoleObj


+(void) PrintToConsole:(NSString *)plainText;


@end


实现:
+(void) PrintToConsole:(NSString *)plainText
{
    NSLog(@"%@" ,plainText);
}


在TestB项目中,先屏蔽原有测试,输入新的测试代码:
[ConsoleObj PrintToConsole:@"The second Test code"];


编译成功,运行出现新的错误:
does not implement methodSignatureForSelector: -- trouble ahead


啊,why?


细细想下以前的代码,没有出现问题呀,为什么这次会出现错误?
回溯检查代码ConsoleObj的代码,仅仅发现一个地方和以前不一样,少了父类NSObject,这个差异的产生是由于直接拷贝原来代码ExtString修改而来的。


好,修改此代码
@interface ConsoleObj:NSObject


+(void) PrintToConsole:(NSString *)plainText;


@end


编译libUtils,再运行测试,没有错误了


现在的情况是:
测试项目调试静态库普通类,没有问题【TestB】
测试项目调试项目自带的扩展方法,也没有问题【TestA】
测试项目测试静态库的扩展方法,出现问题unrecognized selector sent to XXXXXX


没有找到问题所在,借用google,baidu
发现网上的方案:在XCode4下,配置编译选项Other Linker Flags,加入-all_load
(PS:-all_load 告知编译器 所有lib都需要加载)




好,按此方案配置TestB,开启原有测试代码,发现OK了


PS,还有点插曲,我实际的项目中静态库又加了系统自带的库,比如libz等
在测试项目中,需要加这些自带库,不然编译通不过。


最后,要提醒的是:
1、Objective-C自建类的超类一定是NSObject,所以不要省略:FatherClass
一定是这样的:
@interface SonClass:FatherClass
@end


2、扩展方法出现错误unrecognized selector sent to,优先考虑-all_load配置,再考虑内存释放


3、用了-all_load,注意原有引用库文件


3、类别的局限性
有两方面局限性:
    (1)无法向类中添加新的实例变量,类别没有位置容纳实例变量。
       (2)名称冲突,即当类别中的方法与原始类方法名称冲突时,类别具有更高的优先级。类别方法将完全取代初始方法从而无法再使用初始方法。
无法添加实例变量的局限可以使用字典对象解决

4、类别的作用
类别主要有3个作用:
       (1)将类的实现分散到多个不同文件或多个不同框架中。
       (2)创建对私有方法的前向引用。
       (3)向对象添加非正式协议。


三、使用类别创建前向引用
如果其他类中的方法未实现,在你访问其他类的私有方法时编译器报错
这时使用类别,在类别中声明这些方法(不必提供方法实现),编译器就不会再产生警告


不建议在 category 中覆盖类中的方法,因为在 category 中的方法不能调用 superClass 的方法(因为没有元数据支持)
category 方法不能覆盖于同一class 的其它 category 中的方法。因为不法预知他们的加载优先顺序,就可能在编译时出错。
对类库的 category 方法覆盖对导致整个类库的行为发生变化,因此调用那些方法的类不知道方法的实现已经发生了变化。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值