第十八章:Image和鼠标事件
1.NSResponder
NSView继承自NSResponder类。所有的事件处理方法都定义在NSResponder类中。NSResponder申明了如下方法:
- (void)mouseDown:(NSEvent *)theEvent;
- (void)rightMouseDown:(NSEvent *)theEvent;
- (void)otherMouseDown:(NSEvent *)theEvent;
- (void)mouseUp:(NSEvent *)theEvent;
- (void)rightMouseUp:(NSEvent *)theEvent;
- (void)otherMouseUp:(NSEvent *)theEvent;
- (void)mouseDragged:(NSEvent *)theEvent;
- (void)scrollWheel:(NSEvent *)theEvent;
- (void)rightMouseDragged:(NSEvent *)theEvent;
- (void)otherMouseDragged:(NSEvent *)theEvent;
2.NSEvent:一个事件对象包含了所有激发该事件的相关信息。当处理一个鼠标事件时,你应该会对这个方法感兴趣:
- (NSPoint)locationInWindow;//返回事件发生的位置
- (unsigned int)modifierFlags;//返回的整型数告诉你,用户按住了键盘上哪一个修饰键。这让程序员获得如Control-click和Shift-click的组合点击事件:
- (void)mouseDown:(NSEvent*)e { unsigned int flags; flags = [e modifierFlags]; if (flags & NSControlKeyMask){ ...handle control click... } if (flags & NSShiftKeyMask){ ...handle shift click... } }
下面是一些常量,一般对这些修饰标记取AND(&):
NSShiftKeyMask、NSControlKeyMask、NSAlertnateKeyMask、NSCommandKeyMask
- (NSTimeInterval)timestamp;//此方法返回一个按秒计量的时间值,指的是从机器启动开始,到该事件发送时的时间量。NSTimeInterval为double类型
- (NSWindow*)window;//返回发送事件的窗口
- (int)clickCount;//单击、双击还是3击
- (float)pressure;//如果用户使用一个压力输入设备,返回压力值
- (float)deltaX;
- (float)deltaY;
- (float)deltaZ;//这三个方法获得鼠标或滚轮的位置改变量
3.获取鼠标事件——必须在.m文件中重载鼠标事件方法
4.View的坐标系统
如果有两个view,a和b,要将NSPoint p 从b的坐标系统转换到a的坐标系统,可以这样:
NSPoint q = [a coverntPoint:p fromView:b];//如果b为空,将从窗口的坐标系统转换到a的坐标系统
第十九章:键盘事件
1.NSResponder
- (BOOL)acceptsFirstResponder;//将被子类重载,假如需要处理键盘事件则返回YES
- (BOOL)resignFirstResponder;//询问接收对象是否要放弃first-responder状态
- (BOOL)becomeFirstResponder;//通知接收对象成为窗口的first-responder
- (void)keyDown:(NSEvent *)theEvent;//通知接收对象,用户按住了某个键
- (void)keyUp:(NSEvent*)theEvent;
- (void)flagsChanged:(NSEvent*)theEvent;//通知接收对象用户按住或放开了一个修饰键(如Shift或Control)
2.NSEvent——以下通常是用在获得键盘事件信息的方法:
- (NSString *)characters;//返回事件生成的字符
- (BOOL)isARepeat;//当用户按住某键产生重复的键盘事件时返回YES,对于新的键盘事件则返回NO
- (unsigned short)keyCode;//返回事件对应的键盘某个键的编码
- (unsigned int)modifierFlags;//返回一个整型位数来指示对应的修饰键的状况
第二十章:绘制带属性的文本
1.NSFont。NSFont类只有两种类型的方法:
a.得到想要字体的类方法
b.得到字体尺度的方法,如字符的高度
常用方法:
+ (NSFont *)fontWithName:(NSString *)fontName size:(float)fontSize;//fontName是family-face名称。fontSize如果设为0.0,就使用默认的用户字体大小
//下面这些方法返回相对应类型的用户默认字体。如果fontsize为0.0,就使用默认大小
+ (NSFont *)userFixedPitchFontOfSize:(float)fontSize;
+ (NSFont *)userFontOfSize:(float)fontSize;
+ (NSFont *)messageFontOfSize:(float)fontSize;
+ (NSFont *)toolTipsFontOfSize:(float)fontSize;
+ (NSFont *)titleBarFontOfSize:(float)fontSize;
2.NSAttributedString
有时候你希望字符串中的某些字符使用特定的属性来显示。例如,你要显示“Big Nerd Ranch”,并希望给0到2的字符加上下划线,0到7的字符为绿色,9到13的字符显示为下标
Cocoa使用结构NSRange来处理区间。它包含两个整型类型成员—location和length
为了创建特定区间为效果字符的字符串,可以使用Cocoa类NSAttributedString和NSMutableAttributedString:
NSMutableAttributedString *s; s = [[NSMutableAttributedString alloc] initWithString:@"Big Nerd Ranch"]; [s addAttribute:NSFontAttributeName value:[NSFont userFontOfSize:22 range:NSMakeRange(0,14)]; [s addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInt:1] range:NSMakeRange(0,3)]; [s addAttribute:NSForegroundColorAttributeName value:[NSColor greenColor] range:NSMakeRange(0,8)]; [s addAttribute:NSSuperscriptAttributeName value:[NSNumber numberWithInt:-1] range:NSMakeRange(9,5)]; //一旦有了一个属性字符串,就可以给它添加很多要素 [s drawInRect:[self bounds]]; //将它设置给文本框 [textField setAttributedStringValue:s]; //将它设置给按钮 [button setAttributedTitle:s];
NSAttributedString可以读写下面的文件格式:
String:读取一个文本文件
RTF:Rich Text格式是多样字体、多样颜色的文本标准。你可以通过NSData对象来读取或设置属性字符串的内容
RTFD:带有附件的RTF,可以包含图片
HTML:属性字符串可以进行基本的HTML布局,不过最好使用webview
Word:属性字符串可以读写简单地.doc文件
OpenOffice
3.绘制字符串和属性字符串
NSAttributedString:
- (void)drawAtPoint:(NSPoint)aPoint;//绘制字符串,aPoint为字符串的左下角
- (void)drawInRect:(NSRect)rect;//绘制字符串。所有的绘制动作都再rect内部,如果rect装不下,字符串会被裁剪
- (NSSize)size;//返回将会绘制的大小
NSString:
- (void)drawAtPoint:(NSPoint)aPoint withAttributes:(NSDictionary *)attribs//绘制带有attribs属性的字符串
- (void)drawInRect:(NSRect)aRect withAttributes:(NSDictionary *)attribs;
- (NSSize)sizeWithAttributes:(NSDictionary *)attribs;//返回使用属性attribs绘制时所需大小
4.让你的View生成PDF数据
所有的绘制命令都可以通过AppKit框架转换到PDF中。PDF数据可以发生给文件或打印机
你创建一个view,view知道怎么生成pdf数据来描述自己的内容:
- (NSData *)dataWithPDFInisdeRect:(NSRect)aRect;//这个方法会先创建一个数据对象,然后调用drawRect方法。这时这些绘制命令都会绘制到数据对象中,而不再是通常的屏幕。有了数据对象,只需要简单地将它保存到一个文件中
5.NSFontManager:可以显示字体为粗体、斜体或压缩等等
第二十一章:粘贴板和Nil-Targeted Actions
1.粘贴板服务(pasteboard server)(usr/bin/pboard)是Mac系统上运行的一个进程。应用程序使用NSPasteboard类写入数据到该进程,或者从该进程读取数据。粘贴板服务让不同应用程序之间的复制、剪切、粘贴成为可能
NSPasteboard类作为粘贴板服务的接口,下面是它常用的方法:
+ (NSPasteboard *)generalPasteboard;//返回常规的NSPasteboard,你将使用这个粘贴板复制、剪切和粘贴
+ (NSPasteboard *)pasteboardWithName:(NSString*)name;//根据名称返回某个粘贴板
- (int)declareTypes:(NSArray *)types owner:(id)theOwner;//清空粘贴板中得数据,并声明调theOwner复制到粘贴板中得数据的类型
//写输入到粘贴板
- (BOOL)setData:(NSData *)aData forType:(NSString *)dataType;
- (BOOL)setString:(NSString *)s forType:(NSString *)dataType;
- (NSArray *)types;//返回一个数组,包含可以从粘贴板中读取的数据类型
- (NSString *)availableTypeFromArray:(NSArray *)types;//返回粘贴板所能提供的所有数据类型中得第一个
//从粘贴板读取数据
- (NSData *)dataForType:(NSString *)dataType;
- (NSString *)stringForType:(NSString *)dataType;
2.Nil-Targeted Actions
在众多视图中,如何正确地发送cut:、copy:或者paste:消息?——nil-targeted actions
如果一个控件的target为空,应用程序则尝试发送action消息给多个对象,直到它们中的一个有响应。应用程序首先尝试给key window的first responder发送消息
NSView、NSApplication和NSWindow都是继承自NSResponder,它们都有一个实例变量叫nextResponder。如果一个对象不响应nil-targeted acion,它的nextResponder就得到一个机会。
视图的nextResponder通常是它的父视图。window的content view 的nextResponder就是window。因此把responder链接在一起就是响应链(向上回溯)
如何搜索响应链
1)keyWindow的firstResponder以及它的响应链。响应链一般包括父视图以及最终的key window
2)key window的委托
3)如果它是一个文档应用,还包括NSWindowController和key window的NSDocument对象
4)如果main window和key window不同,它还有例行对main window依次检查一遍:
a.main window的firstResponder以及它的响应链,包括main window自己
b.main window的委托
c.NSWindowController和main window的NSDocument对象
5)NSApplication的实例
6)NSApplication的委托
7)NSDocumentController
响应链就是这一系列的对象。对象依次被询问能否响应nil-targeted action
我们知道给nil发送一个消息是不会发生任何事情的。事实上,所有的target/action消息都由NSApplication处理,它又下面这个方法:
- (BOOL)sendAction:(SEL)anAction to:(id)aTarget from:(id)sender;
当target为空时,NSApplication就知道要尝试给响应链上的对象发送消息了
第二十二章:Categories
1.给NSString添加一个方法
#import@interface NSString (FirstLetter) - (NSString*)BNR_firstLetter; @end ------------------------ #import "FirstLetter.h" @implementation NSString (FirstLetter) - (NSString *)BNR_firstLetter { if ([self length] < 2){ return self; } NSRange r; r.location = 0; r.length = 1; return [self substringWithRange:r]; } @end
2.声明私有方法
3.Protocol的非正式写法
第二十三章:拖放
第二十四章:NSTimer
1.NSButton的实例有一个target和一个action(selector)。当按钮按下时,就发送action消息给target。
Timer以相同的方式工作。Timer对象有一个target、一个selector、一个以秒为单位的延时。延时结束后,target会收到selector消息。Timer自己就是消息的参数
2.NSRunLoop
NSRunLoop对象专司等待。它等待事件抵达,然后把事件中转给NSApplication;它等待timer事件,然后把事件中转给NSTimer。你甚至可以附加一个网络socket到循环中,然后它就会等待那个socket上数据的抵达
第二十五章:工作表
1.一个工作表就是一个NSWindow实例,它附属于另外一个窗口。工作表覆盖在窗口上,窗口停止接受事件,直到工作表消失。
NSApplication有下面几个方法来处理工作表:
//启用一个工作表
- (void)beginSheet:(NSWindow *)sheet modalForWindow:(NSWindow *)docWindow modalDelegate:(id)modalDelegate didEndSelector:(SEL)didEndSelector contentInfo:(void*)contextInfo
//结束一个工作表
- (void)endSheet:(NSWindow*)sheet returnCode:(int)returnCode;
2.窗口模式
激活一个工作表后,用户就不能发送事件到宿主窗口。当警告面板(Alert Panel)运行时,它就是模式窗口——即阻止用户给任意其他窗口发送事件:
- (int)runModalForWindow:(NSWindow *)aWindow;//只有发送给aWindow的的事件才会通过这个方法。而要让aWindow成为非模式窗口,可给NSApplication对象发送这个消息:
- (void)stopModalWithCode:(int)returnCode;
第二十六章:创建NSFormatter
1.格式化器 接受一个字符串的输入,生成另外一个对象。如当输入字符串“3/17/1975”,NSDataFormatter就把它转换为一个1975年3月17日的NSData对象
一个格式化器也可以接受一个对象的输入,然后生成一个用于显示的字符串。例如,文本框有一个NSDataFormatter,当文本框收到setObjectValue:的消息,消息参数是一个NSCalendarDate对象,date格式化器就会创建一个字符串代表那个日期,然后用户就看到那个字符串
所有的格式化器都是NSFormatter的子类。Cocoa自带两个子类:NSDateFormatter和NSNumberFormatter
大多数基础格式化器都要实现两个方法:
//用户输入时,控制器(如文本框)要把一个字符串转换为一个对象,它给格式化器发送这个消息。格式化器可以返回YES并把anObject设置为指向新对象的指针。
//如果返回NO,字符串不会被转换,同时设置errorPtr,指出差错所在,errorPtr是一个指向指针的指针。也就是说他是一个让你可以放置一个指向字符串的指针的地方
- (BOOL)getObjectValue:(id*)anObject forString:(NSString *)aString errorDescription:(NSString *)errorPtr;
2.NSControl的委托
在格式化失败后,绑定机制会产生一个警告框。格式化失败也会通知文本框的委托。如果格式化器认为字符串是无效的,委托就会收到下面的报错信息:
- (BOOL)control:(NSControl *)control didFailToFormatString:(NSString *)string errorDescription:(NSString *)error;
3.让格式化器返回Attributed字符串——能让格式化器不仅能决定要显示什么字符串,还能决定如何显示它们:
- (NSAttributedString *)attributedStringForObjectValue:(id)anObj withDefaultAttributes:(NSDictionary *)aDict;
第二十七章:打印
1.处理分页
在你的视图中重载下面的两个方法:
- (BOOL)knowsPageRange:(NSRange *)rptr;//有多少页
- (NSRect)rectForPage:(int)pageNum;//每一个页的位置
第二十八章:Web Service
1.Web Service说到底不过是携带着XML数据的HTTP请求(request)和响应(response)而已
HTTP的请求和响应由NSURL、NSURLRequest、NSURLConnection处理。生成以及解析XML一般由NSXMLDocument和NSXMLNode负责
第二十九章:视图切换
1.相比生成一个新窗口,更常见的情况是用一个视图替换另外一个视图。一个容易的实现方法就是改变box的content view
第三十章:Core Data Relationships
第三十一章:垃圾收集
1.如果仅使用Object-c对象,垃圾收集器可以精准的完成它的工作。但是,只要开始 malloc C数据类型以及Core Foundation structures,就要小心了
当垃圾收集器运行时,它会检索不可到达的对象。你可以把程序中的对象看成一个有向图:这个对象知道那个对象;它知道一些对象,然后这些对象又知道其他的对象,所以垃圾收集器从栈中的指针以及全局变量开始,遍历整个有向图,直到它记下所有的“可到达”对象。不可到达的对象被释放。
2.非对象的数据类型
a. C的原始类型
如果有一个整数缓冲区,当它不可到达时你想让垃圾收集器释放它,这里有一个替代 malloc() 的方法:
int *intBuff = NSAllocateCollectable(100*sizeof(int),0);
当一个“知道”另外一个对象,我们说它有一个引用。引用可以是强或者是弱。垃圾收集器会注意强引用,但会忽略弱引用。因此如果我们只有一个弱引用指向intBuff,它将立即被垃圾收集器释放
弱引用:有时我们需要一个对象指针,只要整个对象存在就一直指向它,但又不想因为这个指针的原因导致整个对象无法被垃圾收集器回传,这种情况使用弱引用
尽管指针还指向这个对象,垃圾收集器还是会释放这个对象。如果指针指向一个已经被释放的对象,它会自动被设置为nil
b.Core Foundation
第三十二章:Core Animation
1.CALayer——可被视为一个供绘制的缓冲区。layer也像视图那样以一定层次结构组织。视图被一个层(layer)覆盖,然后这个层还可以有子层
一旦有了可以高速操纵的CALayer,我们就需要一些东西来驱动这个过程。而CAAnimation就是。NSAnimationContext用来群组以及同步多个animation
常见子类:
CATextLayer:可以更方便地在layer上绘制文本
CAOpenGLLayer:可以更方便调用OpenGL
视图的base layer是_NSViewBackingLayer的实例(不是一个公共类),知道如何绘制它上面的视图的内容
第三十三章:一个简单地Cocoa/OpenGL应用程序
1.NSOpenGLView是NSview的一个子类,有一个OpenGL的绘图上下文。NSOpenGLView的一些重要方法:
- (id)initWithFrame:(NSRect)frameRect pixelFormat:(NSOpenGLPixelFormat *)format;//指定的初始化方法
- (NSOpenGLContext *)openGLContext;//返回视图的OpenGL上下文
- (void)reshape;//当视图调整大小时被调用。这个方法被调用时,OpenGL的上下文是活动的
- (void)drawRect:(NSRect)r;//当视图需要重绘时调用它。这个方法被调用时,OpenGL的上下文是活动的
第三十四章:NSTask
1.你创建的每一个应用都是一个目录,目录里的某处有个可执行文件。要在一个Unix系统上(如Mac)运行可执行程序,首先会fork出一个进程,然后在新进程中执行文件中的代码。
NSTask是一个为了便于使用Unix的fork()和exec()函数的包装器,通过指定一个可执行文件的路径并启动它。很多进程是从标准输入(standard-in)中读取数据并写回到标准输出(standard-out)和标准错误(standard-error)中,应用程序可以用NSTask附加管道(pipe)到外部进程上读取或发送数据,NSPipe类表示管道
2.多线程对多进程