Rails Development Service from China - Home
tag:www.nibirutech.com,2009:mephisto/
Mephisto Drax
2009-01-04T13:22:18Z
lingyun
tag:www.nibirutech.com,2009-01-04:78
2009-01-04T13:20:00Z
2009-01-04T13:22:18Z
userdefault and plist
<p>在目前,我们已经经常用到userdefault了。通过[NSUserDefaults standardUserDefaults],我们便可以得到程序的默认userdefault。
在这里面,我们可以存储一些数据,让程序在启动的获取,来改变一些设置,比如说程序窗口的大小,程序上次退出时的状态等等。
在userdefault里存储新的数据前,我们都需要注册一下,相当于预留一个位置,这样才可以存储。如
if([[NSUserDefaults standardUserDefaults] objectForKey:@”expandedAllItems”] nil)
{</p>
<p>}
userdefault 里可以存储Dictionary, Array, Boolean, Date, Data, Number, String.
简单的int,float类型不能,必须得转化为Number方能存储。
对于较复杂的数据,我们可以存一个Dictionary进去。存Dictionary相对存array来说,好处就相当的明显了,我们在取值时,都特别方便。如:
if(nil [[NSUserDefaults standardUserDefaults] objectForKey:@”tr.immed”])
{</p>
<p>}
之后,才可以在文件里看见它。
比如工程里的Info.plist,该如何获取到呢?
首先我们应该知道,获取到的plist文件,是一个dictionary的格式,获取的方法有两种:
1. [[NSBundle MainBundle] infoDictionary]
通过该函数,返回的dictionary就是我们所要的plist文件的内容
2. [NSDictionary dictionaryWithContentsOfFile:path];
这个path则是plish文件的所在地址,而我们所要获取的Info.plist文件的地址则是在/Contents/ 文件夹下,而不是/Contents/Resources/
这一点需要我们注意。</p>
<pre><code>最后,当我们修改完了之后,需要把内容存起来,那么就需要用到下面这个函数了。
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)flag</code></pre>
<pre><code>非常简单的,就完成了对plist文件的修改</code></pre>
xuzizhan
tag:www.nibirutech.com,2009-01-04:77
2009-01-04T11:49:00Z
2009-01-04T12:28:15Z
stan 12月 技术共享
<p>1.首先要分享的是NSRectArray.经常我们会想使用NSArray或者NSMutableArray来装一些对象。但是NSArray和NSMutableArray都不能装简单类型,比如int,bool或者结构体NSPoint,NSRect这些。但是我们在对诸如NSAttributedString进行一些Rect截取,然后track的时候,往往会需要很多保存NSRect,以便重设的时候删除这些Rect.这下保存这些rect就成了问题。
要说的就是NSRectArray.我们可以如下声明 NSRect aRectArray = <span class="caps">NULL</span>;
aRectArray = 一个返回值为NSRectArray的方法,比如NSLayoutManager的-(NSRectArray)rectArrayForGlyphRange方法。 之后再用
for(int i=0; i<XXX; i++)
{
NSRect gylphrect = aRectArray[i]
}
变可以对每个rect进行操作了</p>
<p>2.其次要说的是关于removeFromSuperView.
我们可以使用NSView 的addSubview方法来增加一个子view,可是NSView确没有 removeSubview.
只能用 NSView的removeFromSuper将自己从superView上移除,而不能方便自由的移除自己身上的subview.这样经常显的很被动。这里分享一下我实现从自己身上移除所有subview的办法。</p>
<p>写一个NSView子类。定义一个叫subViews的成员变量数组。
重载NSView的-(void)didAddSubview:(NSView *)subView方法
-(void)didAddSubview:(NSView *)subView
{</p>
<p>}
这样每次使用addSubView为这个view累增加子view的时候,这个子view都会被同时存入数组
之后写一个叫removeSubviews的方法来移除所有子view
- (void)removeSubviews
{
if([subViews count] <= 0)
return;</p>
<pre><code>for(NSView *aView in subViews)
{</code></pre>
<pre><code>}</code></pre>
<p>}
以后只用方便的调用removeSubviews方法便可以清楚所有子view了。</p>
xuzizhan
tag:www.nibirutech.com,2008-12-09:76
2008-12-09T13:29:00Z
2008-12-09T13:48:45Z
一些易犯不易发现的错误
首先,以前说过,对于NSTextView的string方法并不是返回一个新的NSString对象,而是返回一个指向这个textView的字符串指针,所以当textView中文字改变时,之前返回的那个字符串也会改变。要想返回一个新的string对象需要用[[NSTextView string] copy]
同样,对于NSImage的 imageNamed方法也是一样.通过[NSImage imageNamed:@"xxx"]得到的image对象都是指向xxx这张图片的。比如你在2个类分别用到了
NSImage *image1 = [NSImage imageNamed:@"xxx"];和
NSImage *image2 = [NSImage imageNamed:@"xxx"];
然后你在第一个类中使用了[image1 setFlipped:YES];来把image1翻转。此时你会发现身在另外一个界面的image2也翻转了。解决方法当然还是一样[[NSImage imageNamed:@"xxx"] copy];
另外一个很容易犯,切很难debug的错误就是关于重载方法以后的[super xXX];调用父类方法。
由于对view的逐渐深入的使用,经常会重载诸如mouseDown:(NSEvent *)theEvent 一样的方法,重载时候的想法一般是,“我想在鼠标点击的时候干XXXXX事情”,很久以后会发现一些界面bug,很难找到原因,最后才发现是因为没有调用[super mouseDown:theEvent];意思是你把人家mouseDown本来该干的事情都抹杀掉了。
这些问题都很简单,不过很容易粗心就忽略了,而且很难排查,尽量第一次写到最好才是王道
lingyun
tag:www.nibirutech.com,2008-12-09:75
2008-12-09T09:40:00Z
2008-12-09T09:45:23Z
how to use parameter "..."
<p>在使用NSDictionary的时候,经常使用到一个类方法,如下
<p>+ (id)dictionaryWithObjectsAndKeys:(id)firstObject , ...</p>
<p>该方法后面的… 表明程序员可以在后面添加多个参数,如下面的这个列子</p>
<p>NSDictionary <strong>dict = [NSDictionary dictionaryWithObjectsAndKeys:
<code>"value1", </code>“key1”, <code>"value2", </code>“key2”, nil];</p>
</p>
<p>这主要是通过一个桟实现的。函数中对参数的处理主要是通过对栈进行操作,而c函数的实参都是自右向左压入栈的.</p>
<p>主要的栈操作(都是宏)有va_list,va_start ,va_arg,va_end, 定义如下:</p>
<p>typedef char * va_list;
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) – 1) & ~(sizeof(int) – 1) )
#define va_start _crt_va_start
#define va_arg _crt_va_arg
#define va_end _crt_va_end
#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) – _INTSIZEOF(t)) )
#define _crt_va_end(ap) ( ap = (va_list)0 )</p>
<p>va_start(ap,v):主要是获取可变参数列表的首地址,然后赋值给ap,近似ap=&v+sizeof(v) (这里暂不考虑内存对齐和类型转换)</p>
<p>va_arg(ap,t):取得返回类型t的可变参数值, 并使ap指向下一个参数: ap += sizeof(t),这里的t是可变参数的数据类型,如int,float之类</p>
<p>va_end(ap):结束</p>
<p>va_start(ap,v) va_arg(ap,t) va_end(ap)三者合用,保证程序的健壮性.</p>
<p>下面是我写的一个处理多个通知的函数:</p>
<p>+ (void)addOBserver:(id)notificationObserver withSelectorsAndNotificationNames:(NSString</strong>)firstObject, ...
{
va_list argList; </p>
<pre><code>NSString *selector = firstObject, *notificationName, *currentObject;</code></pre>
<p>//开始 以firstObject为头,获取后面的参数。
va_start(argList,firstObject);</p>
<p>// withSelectorsAndNotificationNames,由于桟里的参数是以两个为一组,于是添加了一个标记量</p>
<p><span class="caps">BOOL</span> flag = NO;
while (currentObject = va_arg(argList, id))//获取id类型的可变参数值,并指向下个,当为nil的时候,退出循环,这也是为什么在多个参数的最后是以nil结尾的。
{
if(flag)
selector = currentObject;
else
{
notificationName = currentObject;
[[NSNotificationCenter defaultCenter] addObserver:notificationObserver
selector:NSSelectorFromString(selector)
name:notificationName
object:nil];
}
flag = !flag;
}
}</p>
<pre><code>va_end(argList);//结束</code></pre>
<p>使用:</p>
<pre><code>[NBUtility addOBserver:self withSelectorsAndNotificationNames:<code>"doPublicTimeline:",</code>"serviceIsPublicTimelineEnabled",
@"refreshOutlineView",REFRESH_OUTLINEVIEW,
<code>"showSendMessageSheet:",</code>“showSendMessageSheet” ,
<code>"expandNewAccount:",</code>“NBAccountAdded”,nil];</code></pre>
<p>需要注意的是参数的顺序,以及末尾以nil结尾。</p>
xuzepei
tag:www.nibirutech.com,2008-12-08:74
2008-12-08T15:55:00Z
2008-12-08T16:00:23Z
设计模式学习体会之Factory模式
<div><font>Factory模式 C++ 代码:</font></div>
<div><br>
<font>#include <stdio.h></font></div>
<div><font>class CFruit<br>
{<br>
public:<br>
virtual void What() = 0;<br>
};</font></div>
<div><font> </font></div>
<div><font>class CApple : public CFruit<br>
{<br>
public:<br>
virtual void What()<br>
{<br>
printf("我是一个苹果\n");<br>
}</font></div>
<div><font><br>
};</font></div>
<div><font> </font></div>
<div><font>class CPear : public CFruit<br>
{<br>
public:<br>
virtual void What()<br>
{<br>
printf("我是一只雪梨\n");<br>
}</font></div>
<div><font><br>
};</font></div>
<div><font> </font></div>
<div><font>class CBanana : public CFruit<br>
{<br>
public:<br>
virtual void What()<br>
{<br>
printf("我是一条香蕉\n");<br>
}</font></div>
<div><font><br>
};</font></div>
<div><br>
<font>enum eFruitType{APPLE=1, PEAR, BANANA};</font></div>
<div><font></font> </div>
<div><font>class CFruitFactory<br>
{<br>
public:</font></div>
<font>
<div><br>
CFruit *GetFruitInstance(eFruitType type)<br>
{</div>
<div><br>
printf("工厂正在生产水果...\n");</div>
<div><br>
switch(type)<br>
{<br>
case APPLE:<br>
return new CApple();<br>
case PEAR: <br>
return new CPear();<br>
case BANANA:<br>
return new CBanana();<br>
default:<br>
return NULL;<br>
}</div>
<div><br>
}</font></div>
<div><font><br>
};</font></div>
<div><br>
<font>int main()<br>
{</font></div>
<font>
<div><br>
CFruitFactory factory;<br>
CFruit *fruit;<br>
<br>
printf("你想吃什么水果?\n");<br>
printf("1 苹果, 2 雪梨, 3 香蕉\n");</div>
<div><br>
int nType = 0;<br>
scanf("%d", &nType);</div>
<div><br>
fruit = factory.GetFruitInstance(eFruitType(nType));<br>
if(fruit == NULL)<br>
{<br>
printf("没有这种水。");<br>
return 0;<br>
}</div>
<div><br>
fruit->What();</font></div>
<p><font> return 0;<br>
}</font></p>
<div> </div>
<div><font>体会:</font></div>
<div><font>(1).可以看出Factory模式将具体Product方法抽象出来(如CFuit是CApple,CPear,CBanana的抽象一样)</font></div>
<div><font>(2).通过一个Factory类来完成根据Product的类型,生产Product的功能,该类具有一个方法,返回抽象Product类的指针(如:CFuit*)</font></div>
<div><font>(3).通过得到的抽象Product的指针,可以调用具体子类的方法。</font></div>
<div><font> </font></div>
<div><font>优点:</font></div>
<div><font>(1)封装<font>创建过程</font>。客户不用知道类厂是如何创建类实例的,类厂封闭了所有创建的细节。这样可选择不同的创建方法,增加了灵活性。 </font></div>
<div><font>(2)将客户与具体类<font>隔离</font>,提高了各自的可重用性。</font></div>
<div><font> <br>
缺点:</font></div>
<div><font>Factory类层次与具体类层次通常是平行的(即一一对应的)。增加一个具体类,一般也要相应地增加一个Factory类,增加了系统复杂度。</font></div>
<br>
liwei
tag:www.nibirutech.com,2008-11-29:73
2008-11-29T01:06:00Z
2008-11-29T01:11:34Z
get text height
do you want to get the height of some text? here is a method.
UILabel *textLabel = [[[UILabel alloc] init] autorelease];
textLabel.text = textWantGetHeight;
textLabel.font = [UIFont systemFontOfSize:13];
textLabel.textAlignment = UITextAlignmentLeft;
textLabel.numberOfLines = 4; //the lines limited
textLabel.lineBreakMode = UILineBreakModeWordWrap;
CGRect frame = [textLabel textRectForBounds:CGRectMake(0, 0,250, 200) limitedToNumberOfLines:4];
frame.size.height is what you want.
houzongming@nibirutech.com
tag:www.nibirutech.com,2008-11-19:72
2008-11-19T09:58:00Z
2008-11-19T10:13:45Z
experience share in Nambu
<p>1, 设置当前程序,使之可以自动运行. </p>
<pre><code>a) NSMutableArray <strong>loginItems = (NSMutableArray</strong>) CFPreferencesCopyValue((CFStringRef)</code></pre>
<pre><code><code>"AutoLaunchedApplicationDictionary", (CFStringRef) </code>"loginwindow",</code></pre>
<pre><code>kCFPreferencesCurrentUser, kCFPreferencesAnyHost);</code></pre>
<pre><code>loginItems = [[loginItems autorelease] mutableCopy];</code></pre>
<pre><code>如此得到所有启动项,其中每个启动项都是个dictionary,启动项有2个key,分别是Hide(BOOL类型), Path(String类型)</code></pre>
<pre><code>b) 删除启动项则 [loginItems removeObject:anItem];</code></pre>
<pre><code>增加启动项则 [loginItems addObject:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO],<code>"Hide", appPath, </code>"Path", nil]];</code></pre>
<pre><code>注:appPath可以 = [[[NSBundle mainBundle] bundlePath] copy]</code></pre>
<pre><code>c) 最后,写回启动项去.</code></pre>
<pre><code>CFPreferencesSetValue((CFStringRef)</code></pre>
<pre><code>@"AutoLaunchedApplicationDictionary", loginItems, (CFStringRef)</code></pre>
<pre><code>@"loginwindow", kCFPreferencesCurrentUser, kCFPreferencesAnyHost);</code></pre>
<pre><code>CFPreferencesSynchronize((CFStringRef) @"loginwindow",</code></pre>
<pre><code>kCFPreferencesCurrentUser, kCFPreferencesAnyHost);</code></pre>
<p>2, 窗口关闭之后,通过点击dock上的图标,再次显示一个窗口的做法.</p>
<p>- (BOOL)applicationShouldHandleReopen:(NSApplication <strong>)theApplication hasVisibleWindows:(BOOL)flag</p>
<p>{</p>
<pre><code>if (flag) </code></pre>
<pre><code>return NO;</code></pre>
<pre><code>else</code></pre>
<pre><code>{</code></pre>
<p>return <span class="caps">YES</span>;</p>
<pre><code>}</code></pre>
<p>}</p>
<p>3, 像sql语句一样,限制返回结果的条数,用setFetchLimit</p>
<p>// get the objects of the entites according predicate and sortDescriptors and limit</p>
<p>+ (NSArray *)objectsEntityForName:(NSString *)entityName</p>
<pre><code>forPredicate:(NSPredicate *)predicate</code></pre>
<pre><code>forSortDescriptors:(NSArray</strong>)sortDescriptors</code></pre>
<pre><code>limit:(NSInteger)limit</code></pre>
<p>{</p>
<pre><code>NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:[NBCoreData managedObjectContext]];</code></pre>
<pre><code>NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];</code></pre>
<p>if(sortDescriptors)</p>
<p>NSArray *objects = [[NBCoreData managedObjectContext] executeFetchRequest:request error:nil];
}</p>
<pre><code>return objects;</code></pre>
<p>4, 高效的通知行高变化,如果你用[NSIndexSet indexSetWithIndexesInRange:0—rowsCount – 1]</p>
liwei
tag:www.nibirutech.com,2008-10-31:71
2008-10-31T09:01:00Z
2008-10-31T09:02:57Z
some thing about keyboard
知道键盘什么时候出现与消失可能是非常有用的,具体实现如下:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow)
name:UIKeyboardWillShowNotification
object:self.view.window];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide)
name:UIKeyboardWillHideNotification
object:self.view.window];
//called the keyboard show.
- (void)keyboardWillShow
{
}
//called the keyboard hide.
- (void)keyboardWillHide
{
}
xuzepei
tag:www.nibirutech.com,2008-10-28:69
2008-10-28T01:08:00Z
2008-10-27T16:10:09Z
Object-C 内存管理小结
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta>
<base>
<style>
/* default css */
table {
font-size: 1em;
line-height: inherit;
}
tr {
text-align: left;
}
div, address, ol, ul, li, option, select {
margin-top: 0px;
margin-bottom: 0px;
}
p {
margin: 0px;
}
body {
margin: 6px;
padding: 0px;
font-family: Verdana, sans-serif;
font-size: 10pt;
background-color: #ffffff;
}
img {
-moz-force-broken-image-icon: 1;
}
@media screen {
html.pageview {
background-color: #f3f3f3 !important;
}
body {
min-height: 1100px;
}
* html body {
height: 1100px;
}
.pageview body {
border-top: 1px solid #ccc;
border-left: 1px solid #ccc;
border-right: 2px solid #bbb;
border-bottom: 2px solid #bbb;
width: 648px !important;
margin: 15px auto 25px;
padding: 40px 50px;
}
/* IE6 */
* html {
overflow-y: scroll;
}
* html.pageview body {
overflow-x: auto;
}
/* Prevent repaint errors when scrolling in Safari. This "Star-7" css hack
targets Safari 3.1, but not WebKit nightlies and presumably Safari 4.
That's OK because this bug is fixed in WebKit nightlies/Safari 4 :-). */
html*#wys_frame::before {
content: '\A0';
position: fixed;
overflow: hidden;
width: 0;
height: 0;
top: 0;
left: 0;
}
.writely-callout-data {
display: none;
}
.writely-footnote-marker {
background-image: url('MISSING');
background-color: transparent;
background-repeat: no-repeat;
width: 7px;
overflow: hidden;
height: 16px;
vertical-align: top;
}
.editor .writely-footnote-marker {
cursor: move;
}
.writely-footnote-marker-highlight {
background-position: -15px 0;
}
.writely-footnote-hide-selection ::-moz-selection, .writely-footnote-hide-selection::-moz-selection {
background: transparent;
}
.writely-footnote-hide-selection ::selection, .writely-footnote-hide-selection::selection {
background: transparent;
}
.writely-footnote-hide-selection {
cursor: move;
}
.editor .writely-comment-yellow {
background-color: #FF9;
background-position: -240px 0;
}
.editor .writely-comment-yellow-hover {
background-color: #FF0;
background-position: -224px 0;
}
.editor .writely-comment-blue {
background-color: #C0D3FF;
background-position: -16px 0;
}
.editor .writely-comment-blue-hover {
background-color: #6292FE;
background-position: 0 0;
}
.editor .writely-comment-orange {
background-color: #FFDEAD;
background-position: -80px 0;
}
.editor .writely-comment-orange-hover {
background-color: #F90;
background-position: -64px 0;
}
.editor .writely-comment-green {
background-color: #99FBB3;
background-position: -48px 0;
}
.editor .writely-comment-green-hover {
background-color: #00F442;
background-position: -32px 0;
}
.editor .writely-comment-cyan {
background-color: #CFF;
background-position: -208px 0;
}
.editor .writely-comment-cyan-hover {
background-color: #0FF;
background-position: -192px 0;
}
.editor .writely-comment-purple {
background-color: #EBCCFF;
background-position: -144px 0;
}
.editor .writely-comment-purple-hover {
background-color: #90F;
background-position: -128px 0;
}
.editor .writely-comment-magenta {
background-color: #FCF;
background-position: -112px 0;
}
.editor .writely-comment-magenta-hover {
background-color: #F0F;
background-position: -96px 0;
}
.editor .writely-comment-red {
background-color: #FFCACA;
background-position: -176px 0;
}
.editor .writely-comment-red-hover {
background-color: #FF7A7A;
background-position: -160px 0;
}
.editor .writely-comment-marker {
background-image: url('MISSING');
background-color: transparent;
padding-right: 11px;
background-repeat: no-repeat;
width: 16px;
height: 16px;
-moz-user-select: none;
}
.editor .writely-comment-hidden {
padding: 0;
background: none;
}
.editor .writely-comment-marker-hidden {
background: none;
padding: 0;
width: 0;
}
.editor .writely-comment-none {
opacity: .2;
filter:progid:DXImageTransform.Microsoft.Alpha(opacity=20);
-moz-opacity: .2;
}
.editor .writely-comment-none-hover {
opacity: .2;
filter:progid:DXImageTransform.Microsoft.Alpha(opacity=20);
-moz-opacity: .2;
}
.br_fix br:not(:-moz-last-node):not(:-moz-first-node) {
position:relative;
left: -1ex
}
.br_fix br+br {
position: static !important
}
}
h6 { font-size: 8pt }
h5 { font-size: 8pt }
h4 { font-size: 10pt }
h3 { font-size: 12pt }
h2 { font-size: 14pt }
h1 { font-size: 18pt }
blockquote {padding: 10px; border: 1px #DDD dashed }
a img {border: 0}
.pb {
border-width: 0;
page-break-after: always;
/* We don't want this to be resizeable, so enforce a width and height
using !important */
height: 1px !important;
width: 100% !important;
}
.editor .pb {
border-top: 1px dashed #C0C0C0;
border-bottom: 1px dashed #C0C0C0;
}
div.google_header, div.google_footer {
position: relative;
margin-top: 1em;
margin-bottom: 1em;
}
/* Table of contents */
.editor div.writely-toc {
background-color: #f3f3f3;
border: 1px solid #ccc;
}
.writely-toc > ol {
padding-left: 3em;
font-weight: bold;
}
ol.writely-toc-subheading {
padding-left: 1em;
font-weight: normal;
}
/* IE6 only */
* html writely-toc ol {
list-style-position: inside;
}
.writely-toc-none {
list-style-type: none;
}
.writely-toc-decimal {
list-style-type: decimal;
}
.writely-toc-upper-alpha {
list-style-type: upper-alpha;
}
.writely-toc-lower-alpha {
list-style-type: lower-alpha;
}
.writely-toc-upper-roman {
list-style-type: upper-roman;
}
.writely-toc-lower-roman {
list-style-type: lower-roman;
}
.writely-toc-disc {
list-style-type: disc;
}
/* end default css */
/* default print css */
@media print {
body {
padding: 0;
margin: 0;
}
div.google_header, div.google_footer {
display: block;
min-height: 0;
border: none;
}
div.google_header {
flow: static(header);
}
/* used to insert page numbers */
div.google_header::before, div.google_footer::before {
position: absolute;
top: 0;
}
div.google_footer {
flow: static(footer);
}
/* always consider this element at the start of the doc */
div#google_footer {
flow: static(footer, start);
}
span.google_pagenumber {
content: counter(page);
}
span.google_pagecount {
content: counter(pages);
}
callout.google_footnote {
display: prince-footnote;
footnote-style-position: inside;
/* These styles keep the footnote from taking on the style of the text
surrounding the footnote marker. They can be overridden in the
document CSS. */
color: #000;
font-family: Verdana;
font-size: 10.0pt;
font-weight: normal;
}
/* Table of contents */
#WritelyTableOfContents a::after {
content: leader('.') target-counter(attr(href), page);
}
#WritelyTableOfContents a {
text-decoration: none;
color: black;
}
}
@page {
@top {
content: flow(header);
}
@bottom {
content: flow(footer);
}
@footnotes {
border-top: solid black thin;
padding-top: 8pt;
}
}
/* end default print css */
/* custom css */
/* end custom css */
/* ui edited css */
body {
font-family: Verdana;
font-size: 10.0pt;
line-height: normal;
background-color: #ffffff;
}
/* end ui edited css */
/* editor CSS */
.editor a:visited {color: #551A8B}
.editor table.zeroBorder {border: 1px dotted gray}
.editor table.zeroBorder td {border: 1px dotted gray}
.editor table.zeroBorder th {border: 1px dotted gray}
.editor div.google_header, .editor div.google_footer {
border: 2px #DDDDDD dashed;
position: static;
width: 100%;
min-height: 2em;
}
.editor .misspell {background-color: yellow}
.editor .writely-comment {
font-size: 9pt;
line-height: 1.4;
padding: 1px;
border: 1px dashed #C0C0C0
}
/* end editor CSS */
</style>
</head>
<body>
<div>
<br>
<font><b>一、非GC(Garbage Collection)模式</b></font>
</div>
<div>
<font></font>
</div>
<div>
<font>1.在非GC模式中,每个对象都有与之关联的引用计数(Reference
Count),当分配或复制对象时(<span class="docEmphStrong"><tt>alloc</tt></span>,
<span class="docEmphStrong"><tt>new</tt></span>, <span class="docEmphStrong"><tt>copy</tt></span>, or
<span class="docEmphStrong"><tt>mutableCopy</tt></span></font><a></a><font>
)引用计数自动设为1。</font>
</div>
<div>
<font></font>
</div>
<div>
<font>2.可以使用release方法将引用计数减1,当引用计数为0时,release方法会调用对象的dealloc方法来销毁对象。</font>
</div>
<div>
<font></font>
</div>
<div>
<font>3.可以使用retain方法来使引用计数加1,保持对象。</font>
</div>
<div>
<font></font>
</div>
<div>
<font>4.如果一个对象被添加到数组,它的引用计数将加1,当该数组被销毁时对象的引用计数将减一。所以为了保证数组销毁时,数组中存放的对象也能销毁。通常我们将一个对象加入数组以后,可以调用release方法将对象引用计数减1.</font>
</div>
<div>
<font></font>
</div>
<div>
<font>exp.</font>
</div>
<div>
<font> LotteryEntry *newEntry;<br>
newEntry = [[LotteryEntry alloc]
initWithEntryDate:iWeeksFromNow];<br>
[array addObject:newEntry];<br>
<span class="docEmphStrong">[newEntry release];</span></font>
</div>
<p>
<span class="docEmphStrong"><font></font></span>
</p>
<div>
<span class="docEmphStrong"><font>5.
数组在添加对象时,并没有拷贝对象,只是保存了对象的指针,并将对象的引用计数加1。当数组销毁时,数组的每个对象都会调用release方法</font></span>
</div>
<p>
<span class="docEmphStrong"><font></font></span>
</p>
<div>
<span class="docEmphStrong"><font>6.在仿问设置属性的方法时,应该先保持在释放</font></span>
</div>
<div>
<span class="docEmphStrong"><font></font></span>
</div>
<div>
<span class="docEmphStrong"><font>exp.</font></span>
</div>
<div>
<span class="docEmphStrong"><font>-
(void)setProperty:(id)newProperty</font></span>
</div>
<div>
<span class="docEmphStrong"><font>{</font></span>
</div>
<div>
<span class="docEmphStrong"><font> [newProperty
retain];</font></span>
</div>
<div>
<span class="docEmphStrong"><font> [property
release];</font></span>
</div>
<div>
<span class="docEmphStrong"><font> property =
newProperty;</font></span>
</div>
<div>
<span class="docEmphStrong"><font>}</font></span>
</div>
<div>
<span class="docEmphStrong"></span>
</div>
<div>
<span class="docEmphStrong"><font>7.autorelease
方法用法标记对象不会被释放直到事件循环结束。每个应用程序都至少有一个自动释放池(autorelease
pool),通过发送autorelease消息可将对象放入池中。在应用程序的事件循环中,当代码执行完毕并将控制权交还给应用程序对象时,应用程序对象会放送一个release消息给自动释放池,而自动释放池再给它包含的每个对象放送release消息。任何引用计数为0的对象就会自动的自我回收。</font></span>
</div>
<div>
<font> </font>
</div>
<div>
<font>8.许多OC类,拥有类的方法,可以直接返回autorelease对象。</font>
</div>
<div>
</div>
<div>
<div>
<font>exp.</font>
</div>
<div>
<font>- (NSString *)description</font>
</div>
<div>
<font>{</font>
</div>
<div>
<font> return [NSString
stringWithFormat:@"%d",count];</font>
</div>
<div>
<font>}</font>
</div>
<div>
</div>
</div>
<div>
</div>
<div>
<font>9. NSObject类的retainCount方法可以返回对象当前的引用计数。</font>
</div>
<div>
</div>
<div>
</div>
<div>
<font><b>二、GC模式</b></font>
</div>
<div>
<b><font></font></b>
</div>
<div>
<font>1.
<font>在GC模式下</font>(<span class="docEmphStrong"><tt>retain</tt></span>,
<span class="docEmphStrong"><tt>release</tt></span>, <span class="docEmphStrong"><tt>autorelease or dealloc)方法被忽略。</tt></span></font>
</div>
<div>
<font><span class="docEmphStrong"><tt></tt></span></font> </div>
<div><span class="docEmphStrong"><tt><font>2.在GC模式下如果想要在对象销毁前做些处理工作,可以重载finalize方法,该方法在对象被销毁前被调用</font></tt></span></div>
<div><span class="docEmphStrong"><tt><font></font></tt></span> </div>
<div><span class="docEmphStrong"><tt><font>exp.</font></tt></span></div>
<div><span class="docEmphStrong"><tt><font>- (void)finalize</font></tt></span></div>
<div><span class="docEmphStrong"><tt><font>{</font></tt></span></div>
<div><span class="docEmphStrong"><tt><font> //you can do some last time stuff here</font></tt></span></div>
<div><span class="docEmphStrong"><tt><font> [super finalize];</font></tt></span></div>
<div><span class="docEmphStrong"><tt><font>}</font></tt></span></div>
<div><span class="docEmphStrong"><tt><font></font></tt></span> </div>
<div><span class="docEmphStrong"><tt><font>3. 非对象数据使用GC</font></tt></span></div>
<div><span class="docEmphStrong"><tt><font></font></tt></span> </div>
<div><span class="docEmphStrong"><tt><font>exp.</font></tt></span></div>
<div><span class="docEmphStrong"><tt><font>int *intBuff;</font></tt></span></div>
<div><span class="docEmphStrong"><tt><font></font></tt></span> </div>
<div><span class="docEmphStrong"><tt><font>setp 1. 使用Strong references声明变量</font></tt></span></div>
<div><span class="docEmphStrong"><tt><font>__strong int *intBuff;</font></tt></span></div>
<div><span class="docEmphStrong"><tt><font></font></tt></span> </div>
<div><span class="docEmphStrong"><tt><font>setp 2. 使用<span class="docEmphStrong"><tt>NSAllocateCollectable方法为变量分配空间,并且将该方法的第2个参数设置为NSScannedOption</tt></span></font></tt></span></div>
<div><span class="docEmphStrong"><tt><font><span class="docEmphStrong"><tt>intBuff= NSAllocateCollectable(100 * sizeof(int), NSScannedOption);</tt></span></font></tt></span></div>
<div><span class="docEmphStrong"><tt><font><span class="docEmphStrong"><tt></tt></span></font></tt></span> </div>
<div><span class="docEmphStrong"><tt><span class="docEmphStrong"><tt><font>4. 对于Core Foundation 数据结构,可以调用CFMakeCollectable方法来使用GC</font></tt></span></tt></span></div>
<div><span class="docEmphStrong"><tt><span class="docEmphStrong"><tt></tt></span></tt></span><font> </font></div>
<div><span class="docEmphStrong"><tt><font>5.GC模式的优缺点:</font></tt></span></div>
<div><span class="docEmphStrong"><tt><font></font></tt></span> </div>
<div><span class="docEmphStrong"><tt><font>优点:</font></tt></span></div>
<div><span class="docEmphStrong"><tt><font> i. 对多线程支持比较好</font></tt></span></div>
<div><span class="docEmphStrong"><tt><font> ii. 减少内存泄漏</font></tt></span></div>
<div><span class="docEmphStrong"><tt><font> iii. 高效的访问方法</font></tt></span></div>
<div><span class="docEmphStrong"><tt><font>缺点:</font></tt></span></div>
<div><span class="docEmphStrong"><tt><font> i.不适应在需要大量创建对象的程序中</font></tt></span></div>
<div><span class="docEmphStrong"><tt><font> ii.对内存的堆栈占用比较大</font></tt></span></div>
<div><span class="docEmphStrong"><tt><font> iii.由于collector运行在线程中,跟非GC的程序相比,更占用cpu</font></tt></span></div>
<div><span class="docEmphStrong"><tt><font></font></tt></span> </div>
<div><span class="docEmphStrong"><tt><font></font></tt></span> </div><br>
xuzizhan
tag:www.nibirutech.com,2008-10-28:70
2008-10-28T00:52:00Z
2008-10-28T00:54:43Z
一个比较隐蔽的错误以及mouseTracking
<p>首先说个很容易忽略,又能耗你很多时间去debug的问题.</p>
<p>最近写代码的时候,遇到一个很囧的错误。众所周知,我们通常建一个controller类,来控制界面。在我这个controller类里,声明了一个 NSTextField *statusText,并在IB里拉上线连接到界面上对应的textField, 这个textField用来显示状态信息。然后在这个controller类里,我想用一个方法来设置这个textField的stringValue,根据命名规范,我把这个方法叫做setStatusText
- (void)setStatusText:(NSString *)newStatus
{
}</p>
<p>在awakeFromNib里,写上[self setStatusText:@”new status”];
编译运行,发现界面上对应的textField地方没有任何东西和文字,用debuger追踪一看,发现[statusText setStringValue:newStatus];中的statusText对象根本不存在.怎么回事呢?
因为,根据key value-coding规则,如果你有一个成员变量叫(id)abc,那么cocoa会自动为你生成(id)abc和setAbc:(id)value;这2个方法用来读取和修改abc.不过系统会查找看你是否已经自己写了这2个方法,如果是,则会调用你自己写的方法来读取和修改。再看这个controller类,我有个成员变量叫statusText,刚好我这个方法叫setStatusText,于是IB在初始化statusText的时候就不会自己init,而是调用我这个setStatusText方法,而这个方法中我自己并没有生成NSTextField对象,因此statusText对象根本就不存在,自然运行以后什么都没有。</p>
<p>一句话来说就是,大家在给方法取名的时候,如果用到setXxxYyy的时候,就要注意xxxYyy是否与你的成员变量重名了。</p>
<p>然后,最近在做一些tool tip window的效果。实现的效果是,当鼠标进入某一个区域(比如一张图片的范围),弹出一个tool tip window,显示相关信息,鼠标在此区域移动时候,窗口跟随鼠标移动,当鼠标移除区域后,窗口消失。
苹果在NSView中提供了- (NSTrackingRectTag)addTrackingRect:(NSRect)aRect owner:(id)userObject userData:(void *)userData assumeInside:(BOOL)flag 方法,顾名思义,trackingRect就是追踪view中一个rect来响应鼠标事件。
返回值NSTrackingRectTag就是一个int,用来标记你添加的这个trackingRect,以便你以后使用-(void)removeTrackingRect:(NSTrackingRectTag)aTag方法来移除它。
aRect自然就是你要响应的区域,这里就设置为图片区域。
owner就是-(void)mouseEntered等方法所在对象了,一般为self。
assumeInside为YES的话,既当trackingRect添加后,就算发现鼠标在其中,也不响应,要等鼠标第一次离开后才开始响应,所以一般设置为NO.
添加区域以后,就在自己的view中重载- (void)mouseEntered:(NSEvent *)theEvent和-(void)mouseExited:(NSEvent *)theEvent方法。顾名思义,当鼠标进入添加的trackingRect区域后,程序会调用mouseEntered方法,移除时调用mouseExited方法,于是只用在这2个方法中分别写上[aWindow orderFront:nil]和[aWindow orderOut:nil].就可实现。</p>
<p>但是还要实现鼠标在区域中移动时窗口跟随移动,而trackingRect并不响应mouseMoved:,
为了更加方便的实现,可以用-(void)addTrackingArea:(NSTrackingArea *)trackingArea,同样是NSView的方法。
用 -(NSTrackingArea *)initWithRect:(NSRect)rect options:(NSTrackingAreaOptions)options owner:(id)owner userInfo:(NSDictionary *)userInfo来生成一个NSTrackingArea对象。
这里rect同样也是响应区域,设置为图片的frame.关键在于options了。NSTrackingAreaOptions是系统定义的全局常量,诸如NSTrackingMouseEnteredAndExited,NSTrackingMouseMoved,NSTrackingCursorUpdate,NSTrackingActiveWhenFirstResponder,NSTrackingActiveInActiveApp,NSTrackingAssumeInside
当需要多个options时候,用按位或符号 | 来连接。顾名思义,我们需要用到NSTrackingMouseEnteredAndExited,NSTrackingMouseMoved
于是我们的options就设置为NSTrackingMouseEnteredAndExited| NSTrackingMouseMoved。
然后在view中重载- (void)mouseEntered:(NSEvent *)theEvent -(void)mouseExited:(NSEvent *)theEvent -(void)mouseMoved:(NSEvent *)theEvent方法。
-(void)mouseMoved:(NSEvent *)theEvent
{
NSPoint aPoint = [NSEvent mouseLocation];</p>
<p>}
便可以实现窗口跟随鼠标移动
最后值得一提的是,window的默认坐标系原点在左下,而需要让window左上角跟随鼠标,因此苹果提供了setFrameTopLeftPoint来设置window的左上角坐标,很方便。</p>
lingyun
tag:www.nibirutech.com,2008-10-27:68
2008-10-27T01:48:00Z
2008-11-14T03:49:41Z
attributed String problem
<p>在nambu的消息显示中,消息有着许多的特殊属性,例如在链接处,需要显示颜色为蓝色,鼠标变为handpointingcursor。但是呢这只是局部,又不能全部设置为这样,于是,就需要我们的NSAttributedString 或 NSMutableAttributedString.
<p>NSMutableAttributedString 中含有这样的一个方法,
– (void)addAttribute:(NSString *)name value:(id)value range:(NSRange)aRange
name 是指需要添加的属性的名字:
NSString *NSFontAttributeName;
NSString *NSParagraphStyleAttributeName;
NSString *NSForegroundColorAttributeName;</p>
...
<p>value 则是对应着不同的name,有着不同的value,比如:
NSFontAttributeName-------Default Helvetica 12-point
NSForegroundColorAttributeName-------blackColor</p>
... <p>range ,则是指我们需要添加属性的范围。
NSForegroundColorAttributeName,
NSFontAttributeName, nil];</p>
<pre><code>即黑色,Helvetica-Bold字体,13号大。</code></pre>
<pre><code>于是,在range的帮助下,我们就可以添加我们所需要的属性。
需要注意的是NSMutableAttributedString 有addAttributes 和 setAttributes 这两个方法。add是指在原有的基础上,继续添加;set是指去掉原来,只有新增的属性。</code></pre>
<pre><code>这样的随意改变属性,就有个潜在的问题了,如何准确的获得这个string的rect呢?不同的字体,不同的大小,会导致rect跟以前的有差距,这样的差距会让信息显示极其不正确。
- (NSRect)boundingRectWithSize:(NSSize)size options:(NSStringDrawingOptions)options
size,可以指定信息显示的宽度或高度,options则是显示的要求。
这样返回的rect,则是我们想要的rect。</code></pre>
<pre><code>例如在nambu的tableview里,它的每一行里,其实是个textfield,当resize tableview时,信息也会随着压缩,使得行数越来越多,那么这是,textfield则需要变换它的高度。
NSRect rect = [attributedMessageText boundingRectWithSize:NSMakeSize([textfield frame].size.width, 0)
options:NSStringDrawingUsesLineFragmentOrigin];</code></pre>
<pre><code>那么,rect.size.height 则是我们所需要的textfield的高度。</code></pre>
</p>
houzongming@nibirutech.com
tag:www.nibirutech.com,2008-10-08:67
2008-10-08T09:06:00Z
2008-10-08T09:08:25Z
setFrame问题
注意,不要把一个subview
[subview setFrame:NSZeroRect];
否则再设置新的frame时,会因为newwidth/0 以及newheight/0都没有意义,而变的无法resize这个subview的子view
这个问题,卡了我几乎一下午的时间。
xuzizhan
tag:www.nibirutech.com,2008-09-23:66
2008-09-23T13:49:00Z
2008-09-24T00:20:20Z
关于NSCell的那些事儿
众所周知,任何一个成功的NSControl(见注释1)背后都有一个NSCell。因为多数功能都可以通过NSControl直接实现,因此NSCell一直是被人忽略的角色。今天就和大家一起走进NSCell的世界,简单谈谈NSCell的常用,实用用法。<br>
<br>
大家打开itunes,mail,或者Finder,都会看到左边的树形列秒(NSOutlineView).每一行,即一个Cell中,既有图片,又有文字。并且整个outlineView只有一列,要实现这种效果,就只有靠操作Cell了。<br>
就以NSOutlineView作为例子。利用outlineView的<br>
<br>
- (<span>id</span>) outlineView: (<span>NSOutlineView</span> *) aOutlineView objectValueForTableColumn: (<span>NSTableColumn</span> *) tableColumn<br>
byItem: (<span>id</span>) item<br>
这个delegate方法可以根据不同节点(item)显示不同的值,当然这个值不能是图片。因此我们要实现左边的图片就只能依靠cell了。<br>
因为apple没有提供一个text and image的NSCell子类,因此我们需要自己建立这样一个类,建立一个新类,取名NBImageAndTextCell(恩,这个名字很规范,很低调又很华丽),并继承至NSTextFieldCell。怎么把这个类和我们的NSControl(即outlineView)联系起来呢,当然NSControl有个叫setCell的方法可以做,但是既然我们有IB(注释2),于是就在IB里设置即可,方便切安全。打开IB选中你的outlineView,再选中其中的column,然后再选中cell。这过程可以通过连续的 command+ctrl+ 方向键下 完成。在cell的inspector窗口(command+shift+I 打开)的identity中将 Class identity改成“NBImageAndTextCell"回车即可,现在我们的cell类就属于这个outlineView了<br>
<br>
<br>
在outlineView的delegate类中使用delegate方法<br>
<br>
- (<span>void</span>)outlineView:(<span>NSOutlineView</span> *)ov willDisplayCell:(NSCell *)cell forTableColumn:(<span>NSTableColumn</span> *)tableColumn item:(<span>id</span>)item<br>
{<br>
<span>NBImageAndTextCell</span> *imageAndTextCell = (<span>NBImageAndTextCell</span> *)cell;<br>
[imageAndTextCell <span>setImage</span>:[<span>item</span> itemImage]];<br>
<br>
}<br>
<br>
顾名思义,"willDisplayCell"就是在即将要显示cell又还没显示cell的那个时候,我们在这个时候把我们要显示的图片通过 setImage 方法 传给cell。 这个image一般就是node的某个属性,这样就可以根据不同的node显示不同的图片。比如Finder中文件夹node的图片就是蓝色小文件夹图<br>
<br>
在 NBImageAndTextCell中声明一个 NSImage *image 和一个- (void)setImage:(NSImage *)anImage;方法。这个setImage方法就是我们上面用到的。<br>
- (<span>void</span>)setImage:(<span>NSImage</span> *)anImage <br>
{<br>
if (anImage != <span>image</span>) <br>
{<br>
[<span>image</span> <span>release</span>];<br>
<span>image</span> = [anImage <span>retain</span>];<br>
}<br>
}<br>
<br>
接下来就是如何在cell中画上这个image的方法了。这是核心所在<br>
- (<span>void</span>)drawWithFrame:(<span>NSRect</span>)cellFrame inView:(<span>NSView</span> *)controlView <br>
{<br>
if (<span>image</span> != nil) <br>
{<br>
[<span>image</span> <span>setSize</span>:(<span>NSSize</span>){16,16}];<br>
<span>NSRect</span> imageFrame;<br>
<span>NSSize</span> imageSize = [<span>image</span> <span>size</span>];<br>
<span>NSDivideRect</span>(cellFrame, &imageFrame, &cellFrame,imageSize.width+5, NSMinXEdge);<br>
if ([<span>self</span> <span>drawsBackground</span>]) {<br>
[[<span>self</span> <span>backgroundColor</span>] <span>set</span>];<br>
<span>NSRectFill</span>(imageFrame);<br>
}<br>
imageFrame.<span>origin</span>.x += 3;<br>
imageFrame.<span>size</span> = imageSize;<br>
<br>
[<span>image</span> <span>compositeToPoint</span>:imageFrame.<span>origin</span> <span>operation</span>:NSCompositeSourceOver];<br>
}<br>
[<span>super</span> <span>drawInteriorWithFrame</span>:cellFrame <span>inView</span>:controlView];<br>
}<br>
<br>
这个draWithFrame继承至NSTextFieldCell,通过这个方法来画上Cell。参数cellFrame就是这个Cell在control(即outlineView)每一行的frame,因此你的outlineView的一行多高多宽,位置在哪儿就是这个cellFrame了。<br>
<br>
看第一句 if (image != nil),这个image是在outlineView的delegate方法里通过setImage传进来的,因此如果我们想要某一个节点没有任何图片的话,就传个nil进来,于是就不会执行括号内画图的方法了。<br>
接下来就是核心<br>
<span>NSDivideRect</span>(cellFrame, &imageFrame, &cellFrame,imageSize.width+5, NSMinXEdge);<br>
<br>
这个NSDivideRect就是一个切割cell的方法,里面的4个参数当然就是决定你怎么切的。<br>
简单来说,<br>
第一个参数是:在哪个里面切 这里是cellFrame,意思是我们在整个cell内切 <br>
第二个:切出来的东西放哪儿 这里是imageFrame一个出参,就是切出来的范围一个Frame 赋给imageFrame<br>
第三个:切剩下的放哪儿 一个出参cellFrame,切后的放入cellFrame,也就说之后的cellFrame就自由我们切剩下的那么大了<br>
第四个:切的边界举例cell边界多远 距离边界imageSize.width+5这么远<br>
第五个:从cell的哪边切 NSMinXEdge是靠cell左边,NSMaxXEdge是右边<br>
<br>
于是现在我们的imageFrame就是我们要放图片的地方和大小,cellFrame就是剩下的cell大小和位置了<br>
<br>
经过小的调整 imageFrame.origin.x += 3; imageFrame.size = imageSize; 后,就调用[image compositeToPoint:imageFrame.origin operation:NSCompositeSourceOver];<br>
在这个范围内画上我们的image即可<br>
<br>
最后千万别忘了[super drawInteriorWithFrame:cellFrame inView:controlView];没有这个,cell都不会被draw上,自然我们切莱切去,画来画去的东西都不能显示了<br>
这个也是我们要继承NSTextFieldCell的原因,就是为了用这个方法。<br>
<br>
ok,大功告成,你的outlineView可以图文并茂了,以后还想切一块出来显示点其他什么图啊什么的,就随便你了。<br>
<br>
<br>
<br>
<br>
小白注释1:NSControl 是NSView子类,如NSTextField,NSButton,NSTableView 等<br>
小白注释2:IB=Interface Builder<br>
houzongming@nibirutech.com
tag:www.nibirutech.com,2008-09-23:65
2008-09-23T13:28:00Z
2008-09-23T14:21:18Z
Source List View (Mail-like) controls
<pre>
大家注意到Mail.app得左下角得,那个add/remove/resize控件了嘛?
<img src="http://bluerope.org/story-media/source-view-controls/full-bar.png">
不少程序都有类似功能,最近也在Nambu.app上作了这个工作。
第一步,加上Source list view controls
把NSSplitView放到window上,加上两个button,选择为Square button,然后分别设置image为NSAddTemplate和NSRemoveTemplate.
第二步,设置这两个button得autoresize类型为保持左、下即可
<img src="http://bluerope.org/story-media/source-view-controls/button-autoresizing.png">
第三步,这两个按钮占用了很少得空间,剩余部分,我们用个custom view来填充,这个view会处理我们第一步添加得splite view得
resize工作,并且会画三条竖线来提示用户那个区域可以作为拖动手柄。添加了custom view后,subclass这个custom view,比如
类名为NBResizeGripView. 这个custom view因为一直要保持与split view左子view同宽,因此autoresize设置为保持左、下、右,
自动放缩宽度。
<img src="http://bluerope.org/story-media/source-view-controls/grip-autoresizing.png">
到这里,我们已经画出了add/remove/resize三个控件了,并且你拉动split view的分界线,也不会出现resize问题
第四步,弄一个类,来做为split view的delegate,不妨叫做NBMainWindowController
第五步,NBMainWindowController加个指向那个resize控件的outlet
IBOutlet NBResizeGripView *splitViewResizer
第六步,告诉split view,你的add/remove/resize控件的尾巴部分(画着三个竖线那块儿)也可以控制split view的大小变化。代码
如下,你要写到你的那个split view的delegate类里。
// NBMainWindow.m
// 除了那个split view分界线外,再设置一个额外的Divider,也就是那个画了三个竖线的区域
-(NSRect)splitView:(NSSplitView *)splitView additionalEffectiveRectOfDividerAtIndex:(NSInteger)dividerIndex
{
NSRect resizeBounds = [splitViewResizer bounds]; // 得到画了三个竖线的区域的bounds
resizeBounds.origin.x = resizeBounds.size.width - 15.0;
resizeBounds.size.width = 15.0;
return [splitViewResizer convertRect:resizeBounds toView:splitView];
}
第七步,就是要让我们的NBResizeGripView能够在右边画三条灰色线了.
// NBResizeGripView.m
- (void)drawRect:(NSRect)rect
{
// fill with gradient
NSRect bounds = self.bounds;
NSColor* color1 = [NSColor colorWithCalibratedRed:249.0/255
green:249.0/255
blue:249.0/255
alpha:1.0];
NSColor* color2 = [NSColor colorWithCalibratedRed:223.0/255
green:223.0/255
blue:223.0/255
alpha:1.0];
NSColor* color3 = [NSColor colorWithCalibratedRed:243.0/255
green:243.0/255
blue:243.0/255
alpha:1.0];
NSGradient* gradient = [[[NSGradient alloc] initWithColorsAndLocations:
color1, 0.0,
color2, 18.0/21.0,
color3, 1.0,
nil]
autorelease];
[gradient drawInRect:bounds angle:90.0];
// draw the top border
NSColor* borderColor = [NSColor grayColor:131.0/255.0];
[borderColor setStroke];
CGFloat y = bounds.size.height;
CGFloat x = bounds.size.width;
[NSBezierPath strokeLineFromPoint:NSMakePoint(0.0, y-0.5)
toPoint:NSMakePoint(x, y-0.5)];
// draw the grip lines
NSColor* gripColor = [NSColor grayColor:(66.0/255.0)];
[gripColor setStroke];
NSInteger lineIndex;
CGFloat lineXPos = x - 4.5;
for (lineIndex = 0; lineIndex < 3; ++lineIndex)
{
[NSBezierPath strokeLineFromPoint:NSMakePoint(lineXPos, 5.5)
toPoint:NSMakePoint(lineXPos, y-5.5)];
lineXPos -= 3.0;
}
}
第八步,完了,build and go.
</pre>
lingyun
tag:www.nibirutech.com,2008-09-23:64
2008-09-23T11:10:00Z
2008-09-24T00:35:29Z
WebView 使用体会
<p>最早接触的,姑且算是这个webkit了吧。
webkit 内就只有webview这一个控件。它也是safari的核心。换句说呢,用了webview,就相当于有一个小型的safari了。</p>
<p>1.引用webkit
首先要导入#import “webkit/webkit.h”</p>
<p>这样就可以声明webview了。</p>
<p>仅仅这些,是不够的。如果运行这样一个程序,会发现有图标在下面一跳一跳的,但是没有界面出来。这是因为需要我们在frameworks里添加webkit.framework。</p>
<p>如此两部分,才算是真正的能用webview了。</p>
<p>2.简易浏览器
IB 给我们提供了一些非常强大的功能,能使得程序员减少许多的代码。
如,一个NSTextField 和 WebView 不用写代码,仅仅在interface builder 就能完成一个简易的浏览器.
按住ctrl,从NSTextField 拖向WebView,选中takeStringURLFrom</p>
<p>就这样,我们的程序完成了,commad+r 运行该界面
在textfield里输入网址,回车,网页便可以浏览了。</p>
<p>3.代码编写
首先这里要提到- (void)awakeFromNib</p>
<p>该函数是专门用于处理ib不能完成的事件,这里最好是只放关于ib的代码。它的执行顺序是在- (id)init 之后。</p>
<p>- (void)awakeFromNib
{</p>
<p>NSString *resourcesPath = [[NSBundle mainBundle] resourcePath];
NSString *htmlPath = [resourcesPath stringByAppendingString:@”/index.html”];</p>
<p>}</p>
<p>在这里,我们设置了webview的delegate,还设置了webview启动时,自动载入index.html这个文件,在webview内显示。
如果时想打开其他的网页的花,则[]NSURL URLWithString:@”www.nibirutetch.com”]。</p>
<p>对于启动以后的操作,则可以在webview的delegate方法 – (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
里面操作。如名字所示,是在webview load 完成之后执行里面的操作。</p>