在chrome和firefox下,使用css的animation,需要先定义一个动画,然后在相应元素的css通过animation
来适用它。如下面例子定义了一个旋转的animation
@keyframes rotate
{
from {transform:rotate(0deg);}
to {transform:rotate(360deg);}
}
XXX {
animation: rotate 1s linear infinite;
}
然而,上面在safari浏览器却不能用,应改成
@-webkit-keyframes rotate
{
from {-webkit-transform:rotate(0deg);}
to {-webkit-transform:rotate(360deg);}
}
XXX {
-webkit-animation: rotate 1s linear infinite;
}
若要兼容两种浏览器,就把上面两个都写上,通过两种方式定义animation即可。
Transition也是动画的一种,可以指定某一个属性变化。
div {
width: 100px;
transition: width 2s linear;
-webkit-transition: width 2s linear;
}
div:hover {
width: 300px;
}
其中,-webkit-transition
是为了兼容safari。
Transform是转换,有以下一系列的动作:
matrix
translate
scale
rotate
skew
perspective
结合transition可以实现很多动画,如
div {
transition: transform 0.5s linear;
-webkit-transition: -webkit-transform 0.5s linear;
}
div:hover {
transform: translate(79px, 0);
-webkit-transform: translate(79px, 0);
}
以上代码可以让div在hover状态向右逐渐位移79px。
Jacob Pan ( jacobpan3g.github.io/cn )
Frameworks
这里很好地简述了cocoa里3个重要库的基本作用
How to Learn
这一段作者的观点很有意思,说要学好新知识有两个技巧
…
In Xcocd - Create a New Project
In Interface Builder - Lay Out the Interface - For the More Curious: XIBs and NIBs
In Interface Builder - The Dock
这里提及了一下Dock下的几个不可见对象(Window,Menu之外的对象):
In Interface Builder - Create a Class
In Interface Builder - The Dock - Create a Class
在写RandomController.h时,使用NSTextField声明变量会报错,因为NSTextField时AppKit的类,这里头文件只包含了Foundation/Foundation.h
,因此会报错。解决方案有两个:
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
直接换成#import <Cocoa/Cocoa.h>
,像AppDelegate.h一样In Interface Builder - Make Connections
首先,需要现在xib添加一个object,在右侧制定是RandomController类
A Look at Objective-C
与Java一样
A Look at Objective-C - Types and Constants in Objective-C
#import
保证只包含一次A Look at Objective-C - Look at the Header File
A Look at Objective-C - Look at the Header File
@interface, @end, @implementation, @class, @selector, @protocol, @property, @synthesize
A Look at Objective-C - Edit the Implementation File
有两种方法:
A Look at Objective-C - Edit the Implementation File
Documentation
Chronology of an Application
NSApplicationMain -> create instance of NSApplication
load NIB file -> every object is called `awakeFormNib`
Main event loop ...
call `terminate()` if quit
Chronology of an Application
苹果用的不是gcc,而是clang/LLVM(Low Level Virtual Machine),也是一个开源编译器
Creating and Using Instances
除了int, char, float等c基本变量
Using Existing Classes
Using Existing Classes
如NSMutableArray的addObject:
是直接把指针添加到数组中,而不会复制对象。
Using Existing Classes
具体请见Table 3.1 Possible Tokens in Objective-C Format Strings
Using Existing Classes
oc函数要定义在以下上下文里
@implementation
...
@end
经试验,也不能在main.h里定义其他C函数。
Using Existing Classes
C String只能保存ascii码,在处理多字节语言时很不方便,如中文,而NSString可以保存Unicode,不用担心本地化问题。
Sending Messages to nil
官方能确定的,接受返回值的若是pointer,值为nil;若为int,值为0;其它类型不确定。
NSObject, NSArray, NSMutableArray, and NSString > NSObject
在NSLog(@"%@", ...)
和gdb中的po
命令都会自动调用description方法。
NSObject, NSArray, NSMutableArray, and NSString > NSObject
对于对象,若没有重载isEqual:方法,以下两句相同,都是比较是否指向同一内存地址(即比较指针里的地址值)
a == b
[a isEqual: b]
NSString的isEqual:已被重载,[str1 isEqual: str2]
比较的是字符的内容,而不是==
的比内存地址。
对于UI控件,一个Button,Target就是与其绑定了Action的Controller,Action就是用户触发动作后发给Controller的消息,即定义在Controller的IBAction方法
发送Action给Target是NSControl类的职责,大部分UI控件都是继承与NSControl,如NSButton,NSTextField等;而NSControl的继承关系是
NSControl->NSView->NSResponder->NSObject
其中NSView负责绘制控件,NSResponder负责相应事件,NSObject提供最基础的init()等方法
ps: 在使用AppKit.framework中,一般不需要继承,直接使用就行
Some Commonly Used Subclasses of NSControl
同时列举了一下所有UI控件。
Lay Out the XIB File
打开Assistance Editor,用ctrl-drag从IB的控件往.h文件拉可以直接生成IBOutlet和IBAction代码
ps: 此处添加代码发现没有-init
函数,就直接添加到applicationDidFinishLaunching:
,效果是一样的
_名字
的私有变量Lay Out the XIB File
同时会生成相应的getter和setter。
Lay Out the XIB File > NSWindow’s initialFirstResponder Outlet
ctrl-click点击(相当于右击)IB里dock的Window对象,把弹出列表中的initialFirstResponder链接到想要第一个相应的控件即可。
For the More Curious: Setting the Target Programmatically
目前提及到设置控件的Action都是通过连线实现的,也可以通过以代码实现,这一节介绍了编译前的做法,和runtime的做法,几点笔记:
SEL
代表函数,可以理解成函数指针@selector(function_name)
与NSSelectorFromString(@"function_name")
的区别: 前者其实是一个宏,在编译时会自动替换成相应的函数,后者是在runtime时候寻找函数的Debugging Hints
这一节让我最深刻的是调试程序crash的方法,可以通过Product-Scheme-Edit Scheme,在左侧选择”Run”,在上面标签选择”Dignostics”,里面有一些调试选择可以帮助定位bug
Challenge
非document-based app只能打开一个,在xcode创建项目时可以选定这个选项
Delegates
这里的delegate,其实就是帮某一个对象去完成一些事情,要成为delegates,主要有3步
感觉就像时配置以下处理函数的感觉,这个不能通过函数指针直接配置进那个对象吗?
缺少的步骤:
<NSTableViewDataSource, NSTableViewDelegate>
(可以不做)收获:
_voice
放到了applicationDidFinishLaunching()里做,需要再加一句[_tableView reloadData]
才能把数据再列表中展现出来,而若放在前二者里就不需要。Edit SpeakLineAppDelegate.m > Common Errors in Implementing a Delegate
即IBOutlet NSTextField和Controller之间也是一种Delegate关系,NSTextField遵守某种Delegate,Controller可以通过调用Delegate里的方法,这些方法可以用来输出或输入。
Starting the RaiseMan Application
Document-based程序工程会自动创建NSDocument子类
Starting the RaiseMan Application
#import <Cocoa/Cocoa.h>
和#import<Foundation/Foundation.h>
是有区别的,前者是包含MacOS所有库,包括GUI和oc;而后者只是oc的库。
所以一些Model类,无需知道UI细节的,应该只包含Foundation.h,这样就能方便移植到命令行项目或ios项目
Starting the RaiseMan Application - RMDocument.xib
在RaiseMan Demo中,通过下面binging动作,NSArrayController的增删查改就能直接操作到Document.h定义的employees数组中:
在xib文件中,添加NSArrayController对象后都dock后,
根据以上步骤,NSArrayController只存在于xib文件中,无需在代码中定义。
Starting the RaiseMan Application - RMDocument.xib
在RaiseMan Demo中,通过Binding可以在xib中借助NSArrayController指定NSTableView Cell的显示内容:
选择第一列TableView Column,在Bind to选择Array Controller,并勾选;在Controller Key填入arrangedObjects,在Model Key Path填入personName(ps: 要显示的Person成员变量名)
同理,第二列Column也是在Binding设置与第一步同样的内容,只是Model Key Path填入另一个成员变量名expectedRaise皆可
这样TableView就会通过NSArrayController获取内容并显示出来。
Starting the RaiseMan Application - RMDocument.xib
添加了Number Formatter后,在用户输入时会检查格式。
Number Formatter是在Xcode 6.2是一个’#’的标识,注意与Text Fieldwith Number Formatter的区分,后者是一个Text Field。
Starting the RaiseMan Application - Key-Value Coding and nil
RaiseMan Demo中,当输入Raise为空时,因无法转换成float,会抛出以下异常并crash:
RaiseMan[1983:303] Exception detected while handling key input.
RaiseMan[1983:303] [<Person 0x60000003b260> setNilValueForKey]: could not set nil as the value for the key expectedRaise.
从异常信息中也可以看到是setNilValueForKey:抛出的异常,setNilValueForKey:是NSObject定义的函数,通过定义Person类中该方法可以处理该异常,具体重载内容请见书中代码。
Multithreading > Simple Cocoa Background Threads
在TableView的DataSouce里,填充的数组不能是
@property (weak) NSArray *results;
而需要定义成私有变量,这样才能让TableView加载成功。
还有,发现DataSouce的tableView:objectValueForTableColumn:row
会被调用很多次,这是为何呢?
Multithreading > Simple Cocoa Background Threads
对于Backgrond Thread,书里没有给出完整的Demo,我根据书忠的代码,写了一个完整的Demo,其中数据源的result需要定义成私有变量,如上一条笔记所说。
ZIPspector
创建Document-Based Application需要制定后缀,首先在project创建页面需要输入后缀,然后在Targget-Info-Document Types中需要选定角色”Viewer/Editor”和填入UTI到identifier处。
测试时run了之后,需要”在menu打开文档”,或者”在文档右击-使用该App打开”才能调试。
ZIPspector
在IB设置UI控件属性需要先选中,在右边的Attribute Inspector的第一行可以看到当前所选择的控件。
先选中TableViewCell,在Inspector第一行显示为”Table Column”,在最下面有一栏state就可以看到。
要改变Cloumn的大小,选中Cloumn后,多点击几次,知道出现边界有一个小方格,就可以通过拖动小方格来调整大小。
ZIPspector
原来NSTableView显示数据只需要把其它类指定为DataSource,而不需要指定Delegate,只有当需要对用户选中Item时响应才需要指定后者。
ZIPspector
当dataSource对象里使用tableView:objectValueForTableColumn:row:
提供内容时,一定要记得把TableView设定成Cell Base,而不是View Base,不然内容会无法填充。
ZIPspector - iPing
原来这种点击一下就变成另外一些内容的按钮时Toggle Button,如看视频的开始暂停按钮,在Inspector把type改为Toggle,填入alternate内容,把State改成Off即可。
ZIPspector - iPing - Figure 36.8 Object Diagram
这里提供了一种思路用来画MacOS基于NIB或者Storyboard开发的程序的框架画法,因为很多connection在IB里完成,代码里根本看不到,所以这种图例用来阐述程序的逻辑非常有用。
ZIPspector - iPing
NSPipe是用来接收NSTask的stdout:
NSPipe *pipe = [[NSPipe alloc] init];
[task setStandardOutput:pipe];
NSFileHandle是NSPipe对象返回的一个对象:
NSFileHandle *fh = [pipe fileHandleForReading];
可以用来读取NSPipe里面的数据,有两种读法:
一种是一次性全部读完,如在ZIPspector例子中
[task waitUntilExit];
NSData *data = [[pipe fileHandleForReading] readDataToEndOfFile];
这种方法需要等task执行完成后才能确保data被全部读出来。
另一种是task每往pipe写一次就读一次,需要借助NSNotification
NSFileHandle *fh = [pipe fileHandleForReading];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc removeObserver:self];
[nc addObserver:self selector:@selector(dataReady:)
name:NSFileHandleReadCompletionNotification object:fh];
[task launch];
[fh readInBackgroundAndNotify];
其中[fh readInBackgroundAndNotify]
是去读fileHandle,读完后产生NSFileHandleReadCompletionNotification
,这个函数是一次性的,因此在绑定notification的dataReay:
方法需要再次调用fh的readInBackgroundAndNotify。
ZIPspector - iPing
iPing例子中用到了两个Notification,第一个是NSFileHandleReadCompletionNotification,当fileHandle的readInBackgroundAndNotify方法读完后发布。
另外一个是Task的NSTaskDidTerminateNotification,当task完成后会发布,利用这个可以在task完成后获取task的执行状态或者做另外一些动作。
ZIPspector
int status = [task terminationStatus];
if (status != 0) {
...
}
通过上述方法可以获取task的返回状态,ZIPspector例子还进一步使用了返回Error的方法
ZIPspector - iPing
在iPing例子中,直接使用NSTextView的NSTextStorage对象,把从pipe通过NSFileHandle读到的数据直接添加到结尾:
NSString *s = [[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding];
NSTextStorage *ts = [outputView textStorage];
[ts replaceCharactersInRange:NSMakeRange([ts length], 0) withString:s];
第一行是从NSData转换成NSString,第三行使用替代函数替代NSRange范围的字符,这里的NSRange是指向数据末尾的,且长度为0,即直接把字符添加到原内容的结尾。
Jacob Pan ( jacobpan3g.github.io/cn )
vim是一个强大的编辑器,虽然它的可拓展性很多现代编辑器都可以做到,如atom,notepad++,但是我觉得vim最大的优势是它是一个命令行工具,很多系统都有内置,根本不用考虑安装问题,一旦配置好了,把配置文件和插件都保存好,同步一下就可以立马搭建好自己最熟悉的开发环境了。
由于vim插件的安装十分分散,与linux的软件安装很像,都是各个文件放在相应的目录下,如语法相关的放在~/.vim/syntax/
下,文件类型相关的放在~/.vim/ftplugin/
下等等,插件安装了之后管理起来比较困难,pathogen这个插件的主要作用就在可以把每个插件都安装在自己的目录下,它会自动生产相应的访问路径供vim访问。
首先在github上下载pathogen的源码,地址在https://github.com/tpope/vim-pathogen.git
创建目录~/.vim/bundle
, 并把pathogen的源码放在该目录下,如~/.vim/bundle/vim-pathogen
。然后在vim配置文件~/.vimrc
添加以下配置:
runtime bundle/vim-pathogen/autoload/pathogen.vim
execute pathogen#infect()
ps: 若配置中有filetype plugin indent on
,pathogen配置要放在它的前面。
安装好了pathogen后,就可以开始安装其他插件了。
taglist是目录插件,可以用于呈现函数列表。原理是通过ctags来匹配出函数名,同理也可以自定义新的规则,拓展taglist。
同样,先从github上下载插件https://github.com/vim-scripts/taglist.vim.git,解压后放到~/.vim/bundle
下,如~/.vim/taglist.vim/
然后在~/.vimrc
添加以下配置
let Tlist_Exit_OnlyWindow=1
这个配置表示当vim只剩下taglist窗口时,会自动退出。更多配置可见插件目录下doc/taglist.txt
。
配置好了后就可以在vim中输入:Tlist
调出左侧的目录窗格。这里可以通过vim绑定按键,如在~/.vimrc
中添加:
nnoremap <silent> <F8> :Tlist<CR>
上面配置时把开启taglist窗格绑定为F8按键。
Jacob Pan ( jacobpan3g.github.io/cn )
在ES6之前,js没有原生实现include包含另一个js模块的功能,ES6推出了import功能,但由于兼容性的考虑,并不能在项目中大胆地使用ES6的新特性。
elem.insertBefore(newElem, beforeElem);
更多请见HTML DOM Element 对象。
Jacob Pan ( jacobpan3g.github.io/cn )