Objective-C日记-之类别Category
类别Category
1,概述
为现有类添加新的方法,这些新方法的Objective-C的术语为“类别”。
2,用法
a,声明类别
@interface NSString(NumberConvenience)
-(Number *)lengthAsNumber;
@end//NumberConvenience
这里类别的名称就叫NumberConvenience,新的类方法为lengthAsNumber.
b,实现类别
@implementation NSString(NumberConvenience)
-(NSNumber *)lengthAsNumber
{
unsigned int length= [self length];
return([NSNumber numberWithUnsignedInt:length]);
}//lengthAsNumber
@end//NumberConvenience
c,类别的使用
如下所示,根据上面定义的类别:NumberConvenience,所有的NSString对象都能响应lengthAsNumber
NUMutableDictionary *dict;
dict = [NSMutableDictionary dictionary];
[dict setObject:[@"hello" lengthAsNumber]
forKey:@"hello"];
[dict setObject:[@"iLikeFish" lengthAsNumber]
forKey:@"iLikeFish"];
[dict setObject:[@"Once upon a time" lengthAsNumber]
forKey:@"Once upon a time"];
NSLog(@"%@",dict);
以上代码将"hello""iLikeFish""Once upon a time"三个字符串与其对应的长度放在了可变字典dict中。
d,类别的不足和作用
类别存在以下不足:一是不能向类别中添加实例变量,二是类别的方法与现有的方法可能存在重名现象,当出现重名时,类别具有更高的优先级。
类别的作用有:
一是将类的实现分散到多个不同的文件或多个不同的框架中。
解释:在通常情况下,我们可以将类的接口放入头文件(.h)中,将实现放在实现文件中(.m),但不能将@implementation放入多个.m文件中,但是类别可以。
以下代码来解释此条作用。
//NSWindows.h
@interface NSWindow:NSResponder
@interface NSWindow(NSKeyboardUI)
@interface NSWindow(NSToolbarSupport)
@interface NSWindow(NSDrag)
@interface NSWindow(NSCarbonExtensions)
@interface NSObject(NSWindowDelegate)
以上是系统自带的NSWidows
以下代码完整的表述了分散实现类别的方法
//.h文件
#import <Foundation/Foundation.h>
@interface CategoryThing:NSObject{
int thing1;
int thing2;
int thing3;
}
@end //CategoryThing
声明完实例变量后,要继续声明类别,这与普通的类有所不同:普通的类将所有的方法都放在接口中声明,类别将每个类别的方法单独声明。如下:
@interface CategoryThing(Thing1)
-(void)setThing1:(int)thing1;
-(int)thing1;
@end //CategoryThing(Thing1)
@interface CategoryThing(Thing2)
-(void)setThing2:(int)thing2;
-(int)thing2;
@end//CategoryThing(Thing2)
@interface CategoryThing(Thing3)
-(void)setThing3:(int)thing3;
-(int)thing3;
@end //CategoryThing(Thing3)
然后,将interface CategoryThing(Thing1),interface CategoryThing(Thing2),interface CategoryThing(Thing3)分别放在Thing1.m,Thing2.m和Thing3.m中实现,如下:
Thing1.m中包含了Thing1类的实现:
#import "CategoryThing.h"
@implementation CategoryThing(Thing1)
-(void)setThing1:(int)t1
{
thing1=t1;
}//setThing1
-(int)thing1
{
return(thing1);
}//thing1
@end//CategoryThing
Thing2.m中包含了Thing2类的实现:
#import "CategoryThing.h"
@implementation CategoryThing(Thing2)
-(void)setThing2:(int)t2
{
thing2=t2;
}//setThing2
-(int)thing2
{
return (thing2);
}//thing2
@end
二是对私有方法的前向引用。
当我们想创建一个类的私有化方法,在OB中好像是不可能的,但是我们可以使用类别来实现。
在OB中可以存在以下情况:我们不在接口中声明某个方法,但我们在实现文件中实现了该方法,并且该方法是可以被调用的,缺点是编译器会报错。
此时,我们就可以使用类别,将该类定义为类别,那么,其中我们就可以不在接口中声明,而在实现中实现并可调用,这种方法被开发人员称作为OB中的私有方法。实现过程如下所示:
@interface Car(PrivateMethods)
-(void)moveTireFromPosition:(int)pos1
toPosition:(int)pos2;
@end//PrivateMethods
以下是方法实现细节
@implementation Car(PrivateMethods)
-(void)moveTireFromPosition:(int)pos1
toPosition:(int)pos2
{
//.....TheImplementation of Methods
}//moveTireFromPosition:toPosition
-(void)rotateTires{
//.....The implementation of methods
}//rotateTires
三是向对象添加非正式协议(informal protocol)。
先讲讲委托(delegation),看了苹果的开发者文档后,我对委托的理解是:将已经固化的一些消息响应操作分离出其原有的动作的一种方法。比如,原本关闭一个窗口是一个已经固化了的操作并不需要我们去实现其具体的细节,但是当我们需要在关闭窗口时还要干点其它的事情,比如保存数据,关闭连接等,就需要接口来帮忙。
它是Cocoa中的类经常使用的一种的技术,委托是一种对象,另一个类的对象会要求委托对象执行它的某些操作。委托是一种设计模式,委托者对象(the delegating object)拥有对委托(the delegate)的引用,委托者对象可以向委托发送消息,委托(the delegate)根据消息来响应某些动作,并通过返回值来反馈自己响应某些动作的结果。
在苹果开发者文档中这样解释委托:
委托是一个对象,当另一个对象遇到一个事件时,代表或者与另一个对象协作来完成某件事。通常情况下,委托者对象(the deletaging object)通常是一个从NSResponder继承而来的用来响应用户事件的响应对象(responsder object)。而委托(the delegate)是授权控制用户接口的对象,或者最起码要以特定的应用方式对事件进行解释。
比如一些窗口对象,早就设计好了主要是用来对譬如放大缩小窗口,关闭窗口,最小化窗口等事件进行响应,这种封闭性的设计肯定会对于这些事件会不会千万其它的影响全然不知,比如将一个窗口关闭,窗口对象早就设计好了如何关闭窗口等等,但是对于关闭窗口这个动作会不会影响数据的保存?网络连接的中断?等等其它状态造成影响,窗口对象完全不知。委托的存在为我们定制的对象和现成的对象之间架起了沟通的桥梁。
通常委托者对象(the delegating object)有一个outlet或者property,通常名字为delegate;如果是outlet,则它另外还含有一个存取outlet的方法。通常还有一个或更多方法的声明,通常是没有实现的,构成了非正式协议或者正式协议。如果是正式协议,则方法声明为optional,通常使用正式协议的方法更为普遍。如下图所示,为委托的图示示例:
协议中的方法通常都标注了需要代理处理的重要的事件。委托者对象(the delegating object)将这些事件或者即将发生的事件传递给委托(delegate object),以请求delegate object有所反映。比如,当一个用户点击窗口的关闭按钮时,窗口对象会改善一个窗口关闭消息给代理,这给代理对象一个机会来决定在关闭窗口时还需要继续完成的事情,如下图所示,窗口对象还需要将数据进行保存。
但是委托者对象delegating object只发送委托delegate定义了的消息。因为这样才可以让NSObject对象的respondsToSelector方法被调用。
通常委托方法的形式比较方便,通常没有UI,NS等前缀,并且名称中常含有动词,如open,或者时态副词,如will,has.心下展示了一些有返回值和没有返回值的委托方法:
- (BOOL)application:(NSApplication *)sender |
openFile:(NSString *)filename; // NSApplication |
- (BOOL)application:(UIApplication *)application |
handleOpenURL:(NSURL *)url; // UIApplicationDelegate |
- (UITableRowIndexSet *)tableView:(NSTableView *)tableView |
willSelectRows:(UITableRowIndexSet *)selection; // UITableViewDelegate |
- (NSRect)windowWillUseStandardFrame:(NSWindow *)window |
defaultFrame:(NSRect)newFrame; // NSWindow |
这些方法可以打断接下来发生的事件,或者改变一个建议值。甚至可以定义一个接下来发生的事件,比如,当一个代理delegate实现了applicationShouldTerminate方法后,可以返回一个NSTerminateLater对象。
以下是一些没有返回值的委托方法,它们是比较纯粹的消息。
- (void) tableView:(NSTableView*)tableView |
mouseDownInHeaderOfTableColumn:(NSTableColumn *)tableColumn; // NSTableView |
- (void)windowDidMove:(NSNotification *)notification; // NSWindow |
- (void)application:(UIApplication *)application |
willChangeStatusBarFrame:(CGRect)newStatusBarFrame; // UIApplication |
- (void)applicationWillBecomeActive:(NSNotification *)notification; // NSApplication |
但是我们来注意一下上图中每二个和第四个方法,其中的参数为NSNotifications对象,这意味着,当这些方法被调用时,会传递一些特定的消息(particular notification)给这些方法,比如windowDidMove:方法就与windows的通知
NSWindowDidMoveNotification
.存在联系。
如何使用委托?
使用非正式协议
使用正式协议,如下所示示例:
//
// main.m
// delegationTest
//
// Created by dbseti on 16/7/21.
// Copyright © 2016年 dbseti. All rights reserved.
//
#import <Foundation/Foundation.h>
@protocol SecProtocol <NSObject>
-(void)payoff;
-(void)tel;
@end
@interface Secret:NSObject<SecProtocol>
@end
@implementation Secret
-(id)init{
if(self=[super init]){
}
return self;
}
-(void)payoff{
NSLog(@"secret payoff");
}
-(void)tel{
NSLog(@"secret tel");
}
@end
@interface Boss:NSObject
@property (nonatomic,retain) id <SecProtocol> delegate;
-(void)manager;
-(void)teach;
@end
@implementation Boss
@synthesize delegate=_delegate;
-(id)init{
if(self=[super init]){
}
return self;
}
-(void)manager{
NSLog(@"Boss manage");
}
-(void)teach{
NSLog(@"Boss teach");
}
-(void)payoff{
[_delegate payoff];
}
-(void)tel{
[_delegate tel];
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Secret *sec=[[Secret alloc]init];
Boss *b=[[Boss alloc]init];
b.delegate=sec;//这一步很关键,它将sec赋给b的代理delegate,实际上还是由b的成员来执行了这个操作
[b teach];
[b manager];
[b payoff];
[b tel];
// insert code here...
NSLog(@"Hello, World!");
}
return 0;
}
以下图片显示了他们的逻辑关系。
什么协议都不使用
背影条件:有对象A和对象B,对象A有一个方法p,对象B没有方法p,但是它想使用方法p,它让A去调用p方法,这个是最基本的委托。(其实按我个人的理解,这个根本就是调用A对象中方法p)没有太多的新的概念和方法。
@interface A:NSObject
-(void)p;
@end
@implementation A
-(void)p
{
NSLog(@"I am A's method p");
}
@end
@interface B:NSObject
{
A* delegate;
}
@property (nocopy,retain) A* delegate;
@end
@implementation B
@synthesize A*delegate;
@end
void main(){
B * b=[[B alloc] init];
A * a=[[A alloc] init];
b.delegate=a;
[b.delegate p];
}
还有一种方式,如下所示A类包含B类的一个对象和一个print方法,在A类实现的时候,多了一个方法viewDidLoad和一个特性delegate;B类包含一个类型为id的delegate
@interface A:NSObject{
B *b;
}
-(void)print;
@end
@implementation A
@synthesize delegate;
-(void)viewDidLoad{
b=[[B alloc]init];
b.delegate=self;
}
-(void)print{
NSLog(@"print was called");
}
@interface B:NSObject{
id delegate;}
@property(nonmatic,retain) id delegate;
@end
@implementation B
-(void)callPrint{
[self.delegate print];
}
@end
Objective-C日记-之类别Category的更多相关文章
- 类别(Category)与扩展(Extensions)
一.类别(Category) 类别(Category)是一种可以为现有的类(包括类簇:NSString...,甚至源码无法获得的类)添加新方法的方式无需从现有的类继承子类.类别添加的新方法可以被子类继 ...
- iOS类别(Category)
iOS类别(Category)与扩展(Extension) 苹果的官方文档 Category在iOS开发中使用非常频繁.尤其是在为系统类进行拓展的时候,我们可以不用继承系统类,直接给系统类添加方法,最 ...
- Objective-C 类别(category)和扩展(Extension)
1.类别(category) 使用Object-C中的分类,是一种编译时的手段,允许我们通过给一个类添加方法来扩充它(但是通过category不能添加新的实例变量),并且我们不需要访问类中的代码就可以 ...
- 分类(类别/Category)与 类扩展(Extension)
一.分类(类别/Category) 1.适用范围 当你已经封装好了一个类(也可能是系统类.第三方库),不想在改动这个类了,可是随着程序功能的增加需要在类中增加一个方法,这时我们不必修改主类, ...
- iOS类别(Category)与扩展(Extension)-b
苹果的官方文档 Category在iOS开发中使用非常频繁.尤其是在为系统类进行拓展的时候,我们可以不用继承系统类,直接给系统类添加方法,最大程度的体现了Objective-C的动态语言特性. #im ...
- iOS类别(Category)和扩展(Extension,匿名类)
Category在iOS在开发常用. 特别是对于系统扩展上课时间.我们不能继承系统类.直接添加到系统类方法,最大程度上体现Objective-C动态语言特征. #import @interface N ...
- ios 类别(category)
定义 类别(category)是Objective-C语言的新特性,为现有的类添加新方法的方式.局限性:1.无法添加新的实例变量.2.与类本身的方法名称冲突.当名称冲突时,类别具有更高的优先级.作用: ...
- OC学习笔记——类别(Category)
类别,有些程序员又称之为分类. 类别是一种为现有的类添加新方法的方式,尤其是为系统的做扩展的时候,不用继承系统类,可以直接为类添加新的方法.也可以覆盖系统类的方法. 如: @interface NSO ...
- Objective-C中的协议(Protocol)和类别(Category)
1.什么是协议? 2.协议与类别的声明和使用 1.什么是协议? 在Objective-C中,不支持多继承,即不允许一个类有多个父类,但是OC提供了类似的实现方法,也就是协议.协议有点类似于Java里的 ...
随机推荐
- Win10下CISCO VPN Client无法安装解决方案
Cisco vpn client 在Windows升级到Windows 10 之后无法正常安装使用,在这种情况下:1.先安装Dell SonicWALL Global VPN Client(GVCSe ...
- 界面编程与视图(View)组件
一.视图组件与容器组件 Android应用的绝大部分UI组件都放在android.widget包及其子包.android.view包及其子包中,Android应用的所有UI组件都继承了View类. V ...
- HTML 多媒体、Object 元素、音频、视频
Web 上的多媒体指的是音效.音乐.视频和动画. 现代网络浏览器已支持很多多媒体格式. 什么是多媒体? 多媒体来自多种不同的格式.它可以是您听到或看到的任何内容,文字.图片.音乐.音效.录音.电影.动 ...
- Canvas createRadialGradient API
Canvas createRadialGradient API <!DOCTYPE html> <html lang="en"> <head> ...
- canvas小程序-快跑程序员
canvas不用说html5带来的好东西,游戏什么的,么么哒 记得有一天玩手机游戏,就是一个跳跃过柱子那种,其实元素很简单啊,app能开发,借助html5 canvas也可以啊, 于是就开始了. -- ...
- 从零开始学C#——基本语法(二)
基本语法 C#,又名Csharp,天朝喜欢叫C井. C#是一种面向对象的编程语言.在面向对象的程序设计方法中,程序有各种相互交互的对象组成.相同种类的对象通常具有相同的类型,或者说,是在先沟通那个的c ...
- css3 过渡和2d变换——回顾
1.transition 语法:transition: property duration timing-function delay; transition-property 设置过渡效果的css ...
- Unity起步-1.1下载和安装Unity
1.1.下载和安装Unity 1.1.1 选取版本 首先找到Unity官方网站https://store.unity.com/cn,如果要下载最新版本,可以选择"立即下载".不过我 ...
- (3)activiti流程的挂起和激活
有时候,我们需要对一个已经执行的流程进行暂停,而不是删除它,这个时候就需要我们调用activiti暂停和激活的api来操作他们 每启动一个流程实例,都会在该流程实例下产生相应的流程任务,处于1*多的关 ...
- 《无所不能的JavaScript编程系列:arguments 参数对象》
前言:无所不能的JavaScript JavaScript起源于Netscape公司的LiveScript语言,这是一种基于对象和事件驱动的客户端脚本语言,最初的设计是为了检验HTML表单输入的正确性 ...