Rails Development Service from China - Home tag:www.nibirutech.com,2008:mephisto/ Mephisto Drax 2008-11-19T10:13:45Z 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 内存管理小结 &lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> &lt;html> &lt;head> &lt;meta> &lt;base> &lt;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 */ &lt;/style> &lt;/head> &lt;body> <div> <br> &lt;font><b>一、非GC(Garbage Collection)模式</b>&lt;/font> </div> <div> &lt;font>&lt;/font>&nbsp; </div> <div> &lt;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>,&nbsp;or <span class="docEmphStrong"><tt>mutableCopy</tt></span>&lt;/font><a></a>&lt;font> )引用计数自动设为1。&lt;/font> </div> <div> &lt;font>&lt;/font>&nbsp; </div> <div> &lt;font>2.可以使用release方法将引用计数减1,当引用计数为0时,release方法会调用对象的dealloc方法来销毁对象。&lt;/font> </div> <div> &lt;font>&lt;/font>&nbsp; </div> <div> &lt;font>3.可以使用retain方法来使引用计数加1,保持对象。&lt;/font> </div> <div> &lt;font>&lt;/font>&nbsp; </div> <div> &lt;font>4.如果一个对象被添加到数组,它的引用计数将加1,当该数组被销毁时对象的引用计数将减一。所以为了保证数组销毁时,数组中存放的对象也能销毁。通常我们将一个对象加入数组以后,可以调用release方法将对象引用计数减1.&lt;/font> </div> <div> &lt;font>&lt;/font>&nbsp; </div> <div> &lt;font>exp.&lt;/font> </div> <div> &lt;font>&nbsp;&nbsp;&nbsp; LotteryEntry *newEntry;<br> &nbsp;&nbsp;&nbsp; newEntry = [[LotteryEntry alloc] initWithEntryDate:iWeeksFromNow];<br> &nbsp;&nbsp;&nbsp; [array addObject:newEntry];<br> &nbsp;&nbsp;&nbsp; <span class="docEmphStrong">[newEntry release];</span>&lt;/font> </div> <p> <span class="docEmphStrong">&lt;font>&lt;/font></span>&nbsp; </p> <div> <span class="docEmphStrong">&lt;font>5. 数组在添加对象时,并没有拷贝对象,只是保存了对象的指针,并将对象的引用计数加1。当数组销毁时,数组的每个对象都会调用release方法&lt;/font></span> </div> <p> <span class="docEmphStrong">&lt;font>&lt;/font></span>&nbsp; </p> <div> <span class="docEmphStrong">&lt;font>6.在仿问设置属性的方法时,应该先保持在释放&lt;/font></span> </div> <div> <span class="docEmphStrong">&lt;font>&lt;/font></span>&nbsp; </div> <div> <span class="docEmphStrong">&lt;font>exp.&lt;/font></span> </div> <div> <span class="docEmphStrong">&lt;font>- (void)setProperty:(id)newProperty&lt;/font></span> </div> <div> <span class="docEmphStrong">&lt;font>{&lt;/font></span> </div> <div> <span class="docEmphStrong">&lt;font>&nbsp;&nbsp;&nbsp;&nbsp;[newProperty retain];&lt;/font></span> </div> <div> <span class="docEmphStrong">&lt;font>&nbsp;&nbsp;&nbsp; [property release];&lt;/font></span> </div> <div> <span class="docEmphStrong">&lt;font>&nbsp;&nbsp;&nbsp; property = newProperty;&lt;/font></span> </div> <div> <span class="docEmphStrong">&lt;font>}&lt;/font></span> </div> <div> <span class="docEmphStrong"></span>&nbsp; </div> <div> <span class="docEmphStrong">&lt;font>7.autorelease 方法用法标记对象不会被释放直到事件循环结束。每个应用程序都至少有一个自动释放池(autorelease pool),通过发送autorelease消息可将对象放入池中。在应用程序的事件循环中,当代码执行完毕并将控制权交还给应用程序对象时,应用程序对象会放送一个release消息给自动释放池,而自动释放池再给它包含的每个对象放送release消息。任何引用计数为0的对象就会自动的自我回收。&lt;/font></span> </div> <div> &lt;font>&nbsp;&lt;/font> </div> <div> &lt;font>8.许多OC类,拥有类的方法,可以直接返回autorelease对象。&lt;/font> </div> <div> &nbsp; </div> <div> <div> &lt;font>exp.&lt;/font> </div> <div> &lt;font>- (NSString *)description&lt;/font> </div> <div> &lt;font>{&lt;/font> </div> <div> &lt;font>&nbsp;&nbsp; return [NSString stringWithFormat:@"%d",count];&lt;/font> </div> <div> &lt;font>}&lt;/font> </div> <div> &nbsp; </div> </div> <div> &nbsp; </div> <div> &lt;font>9. NSObject类的retainCount方法可以返回对象当前的引用计数。&lt;/font> </div> <div> &nbsp; </div> <div> &nbsp; </div> <div> &lt;font><b>二、GC模式</b>&lt;/font> </div> <div> <b>&lt;font>&lt;/font></b>&nbsp; </div> <div> &lt;font>1. &lt;font>在GC模式下&lt;/font>(<span class="docEmphStrong"><tt>retain</tt></span>, <span class="docEmphStrong"><tt>release</tt></span>,&nbsp; <span class="docEmphStrong"><tt>autorelease or dealloc)方法被忽略。</tt></span>&lt;/font> </div> <div> &lt;font><span class="docEmphStrong"><tt></tt></span>&lt;/font>&nbsp;</div> <div><span class="docEmphStrong"><tt>&lt;font>2.在GC模式下如果想要在对象销毁前做些处理工作,可以重载finalize方法,该方法在对象被销毁前被调用&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font>&lt;/font></tt></span>&nbsp;</div> <div><span class="docEmphStrong"><tt>&lt;font>exp.&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font>- (void)finalize&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font>{&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font>&nbsp;&nbsp; //you can do some last time stuff here&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font>&nbsp;&nbsp;&nbsp;[super finalize];&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font>}&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font>&lt;/font></tt></span>&nbsp;</div> <div><span class="docEmphStrong"><tt>&lt;font>3. 非对象数据使用GC&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font>&lt;/font></tt></span>&nbsp;</div> <div><span class="docEmphStrong"><tt>&lt;font>exp.&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font>int *intBuff;&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font>&lt;/font></tt></span>&nbsp;</div> <div><span class="docEmphStrong"><tt>&lt;font>setp 1. 使用Strong references声明变量&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font>__strong int *intBuff;&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font>&lt;/font></tt></span>&nbsp;</div> <div><span class="docEmphStrong"><tt>&lt;font>setp 2. 使用<span class="docEmphStrong"><tt>NSAllocateCollectable方法为变量分配空间,并且将该方法的第2个参数设置为NSScannedOption</tt></span>&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font><span class="docEmphStrong"><tt>intBuff= NSAllocateCollectable(100 * sizeof(int), NSScannedOption);</tt></span>&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font><span class="docEmphStrong"><tt></tt></span>&lt;/font></tt></span>&nbsp;</div> <div><span class="docEmphStrong"><tt><span class="docEmphStrong"><tt>&lt;font>4. 对于Core Foundation 数据结构,可以调用CFMakeCollectable方法来使用GC&lt;/font></tt></span></tt></span></div> <div><span class="docEmphStrong"><tt><span class="docEmphStrong"><tt></tt></span></tt></span>&lt;font>&nbsp;&lt;/font></div> <div><span class="docEmphStrong"><tt>&lt;font>5.GC模式的优缺点:&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font>&lt;/font></tt></span>&nbsp;</div> <div><span class="docEmphStrong"><tt>&lt;font>优点:&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font>&nbsp;&nbsp;&nbsp; i. 对多线程支持比较好&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font>&nbsp;&nbsp;&nbsp; ii. 减少内存泄漏&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font>&nbsp;&nbsp;&nbsp;&nbsp;iii. 高效的访问方法&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font>缺点:&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font>&nbsp;&nbsp;&nbsp;&nbsp;i.不适应在需要大量创建对象的程序中&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font>&nbsp;&nbsp;&nbsp;&nbsp;ii.对内存的堆栈占用比较大&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font>&nbsp;&nbsp;&nbsp;&nbsp;iii.由于collector运行在线程中,跟非GC的程序相比,更占用cpu&lt;/font></tt></span></div> <div><span class="docEmphStrong"><tt>&lt;font>&lt;/font></tt></span>&nbsp;</div> <div><span class="docEmphStrong"><tt>&lt;font>&lt;/font></tt></span>&nbsp;</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> &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 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> &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span>NBImageAndTextCell</span> *imageAndTextCell = (<span>NBImageAndTextCell</span> *)cell;<br> &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [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> &nbsp;&nbsp;&nbsp; if (anImage != <span>image</span>) <br> &nbsp;&nbsp;&nbsp; {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [<span>image</span> <span>release</span>];<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>image</span> = [anImage <span>retain</span>];<br> &nbsp;&nbsp;&nbsp; }<br> }<br> <br> 接下来就是如何在cell中画上这个image的方法了。这是核心所在<br> - (<span>void</span>)drawWithFrame:(<span>NSRect</span>)cellFrame inView:(<span>NSView</span> *)controlView <br> {<br> &nbsp;&nbsp;&nbsp; if (<span>image</span> != nil)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br> &nbsp;&nbsp;&nbsp; {<br> &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; [<span>image</span> <span>setSize</span>:(<span>NSSize</span>){16,16}];<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>NSRect</span>&nbsp;&nbsp;&nbsp; imageFrame;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>NSSize</span> imageSize = [<span>image</span> <span>size</span>];<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>NSDivideRect</span>(cellFrame, &amp;imageFrame, &amp;cellFrame,imageSize.width+5, NSMinXEdge);<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ([<span>self</span> <span>drawsBackground</span>]) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [[<span>self</span> <span>backgroundColor</span>] <span>set</span>];<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>NSRectFill</span>(imageFrame);<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; imageFrame.<span>origin</span>.x += 3;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; imageFrame.<span>size</span> = imageSize;<br> &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [<span>image</span> <span>compositeToPoint</span>:imageFrame.<span>origin</span> <span>operation</span>:NSCompositeSourceOver];<br> &nbsp;&nbsp;&nbsp; }<br> &nbsp;&nbsp;&nbsp; [<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, &amp;imageFrame, &amp;cellFrame,imageSize.width+5, NSMinXEdge);<br> <br> 这个NSDivideRect就是一个切割cell的方法,里面的4个参数当然就是决定你怎么切的。<br> 简单来说,<br> 第一个参数是:在哪个里面切&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这里是cellFrame,意思是我们在整个cell内切 <br> 第二个:切出来的东西放哪儿&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这里是imageFrame一个出参,就是切出来的范围一个Frame 赋给imageFrame<br> 第三个:切剩下的放哪儿&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一个出参cellFrame,切后的放入cellFrame,也就说之后的cellFrame就自由我们切剩下的那么大了<br> 第四个:切的边界举例cell边界多远&nbsp;&nbsp; 距离边界imageSize.width+5这么远<br> 第五个:从cell的哪边切&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NSMinXEdge是靠cell左边,NSMaxXEdge是右边<br> <br> 于是现在我们的imageFrame就是我们要放图片的地方和大小,cellFrame就是剩下的cell大小和位置了<br> <br> 经过小的调整 imageFrame.origin.x += 3;&nbsp; imageFrame.size = imageSize;&nbsp; 后,就调用[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 &lt; 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> zhangtongjie tag:www.nibirutech.com,2008-09-23:63 2008-09-23T02:19:00Z 2008-09-23T02:21:25Z Mac OS环境下编译使用Gloox 一、gloox简介 gloox是一个多功能的 C++ XMPP library,主要的新功能包括: - 完整的 MUC 支持 - 文件传输 (XEPs 0065, 0095, 0096) - XPath支持 更多信息参http://camaya.net/gloox 二、准备工作 操作系统:Mac OS 10.5.3 编译器:gcc 4.0 编译Gloox需要的源代码包有: gloox http://camaya.net/glooxdownload libidn http://www.gnu.org/software/libidn/ guntls http://www.gnu.org/software/gnutls/ openssl http://www.openssl.org/ zlib http://www.zlib.net/ libgpg-error ftp://ftp.gnupg.org/gcrypt/libgpg-error/libgpg-error-1.6.tar.bz2 libgcrypt http://mirrors.rootmode.com/ftp.gnupg.org/libgcrypt/ 三、编译gloox 在GNU开源项目中,标准的编译安装步骤是: 1、解压源代码包文件,命令为: tar xvf XXX.tar 解压以tar结尾的文件 tar jxvf XXX.tar.bz2 解压以tar.bz结尾的文件 tar zxvf XXX.tar.gz 解压以tar.gz结尾的文件 2、进入解压后的文件目录,运行 ./configure 3、编译源代码 make 4、安装 make install 编译后默认的安装位置是/usr/local 目录,即头文件放在/usr/local/include ,库文件放在/usr/local/lib,但在make install的时候会报“ Permission denied”的错误(如图1)。原因是在mac os上用户是没有权限在/usr/local/目录上做修改。这时我们可以重新设置安装目录,以$HOME/src目录为例,重新运行. /configure使用--prefix指明其安装路径 ./configure --prefix=$HOME/src 然后在运行 make;make install 图1 Premission denied 错误 设置package路径 当我们编译安装完一个库后,往往会生成一个以.pc结尾的文件,这个文件包含了这个库的一些基本信息,如安装路径(prefix),头文件路径(includedir),库文件路径(libdir)等等。通过这个文件,系统就能够识别到已经安装了这个库。但您需要先设置 PKG_CONFIG_PATH环境变量(假如.pc文件路径为${HOME}/src/lib/pkgconfig) export PKG_CONFIG_PATH=${HOME}/src/lib/pkgconfig 这时您可以使用命令查看所有已安装的库 pkg-config --list-all 依次 编译zlib: ./configure --prefix=$HOME/src;make;make install 编译libidn: ./configure --prefix=$HOME/src;make;make install 编译openssl (编译openssl的时候,使用命令./config 而不是./configure) ./config --prefix=$HOME/src;make;make install 编译libgpg-error ./configure --prefix=$HOME/src;make;make install 编译libgcrypto:(直接运行./configure的时候会出错,提示需要libgpg-error,使用./configure --help查看用法,找到--with-gpg-error-prefix选项,用于设置libgpg的安装路径) ./configure --prefix=$HOME/src --with-gpg-error-prefix=$HOME/src;make;make install 编译gnutls: ./configure --prefix=$HOME/src --with-libgcrypt-prefix=$HOME/src;make;make install 编译gloox稍微麻烦一点,需要修改几个文件 修改文件 :$HOME/src/gloox-0.9.9.5/src/tlsopenssl.cpp 第226行,”std::tolower”为“tolower” 修改文件 :$HOME/src/include/gnutls/gnutls.h 第290行,去掉 “GNUTLS_CRT_PRINT_UNSIGNED_FULL,“后的”,“ 修改文件:./configure 第20801行,“libgnutls-config --libs“改为” pkg-config --libs gnutls “ 运行(使用CXXFLAGS=-Wno-long-long选项,是为了编译long long 类型的变量不报错) ./configure CXXFLAGS=-Wno-long-long --prefix=$HOME/src --with-libidn=$HOME/src --with-gnutls=$HOME/src --with-openssl=$HOME/src 全部编译完成以后,就可以在 $HOME/src/lib中看到所有已经编译好的静态库(.a)和动态库(.dylib)文件,部分库编译的时候没有生成动态库,需要重新运行configure,添加--shared参数编译生成。 对于静态库,您可以直接使用 对于动态库,使用的时候需要注意几点: Mac OS的动态库连接路径使用的是绝对路径,您可以通过命令otool来查看其连接路径(如图2) otool -L libgloox.dylib 图2 使用otool 查看动态库连接路径 当您把这些库拷贝到另外一台机器上的时候,就会发生加载动态库出错。因为其他机器上在该绝对路径上并不能找到该动态库。 解决方法是使用install_name_tool命令来修改动态库连接路径 修改当前库连接路径 install_name_tool -id @executable_path/libgloox.dylib libgloox.dylib 修改依赖库连接路径(系统库的路径不用修改,如libiconv.2.dylib) install_name_tool -change /Users/ztj/src/lib/libidn.11.dylib @executable_path/libidn.11.dylib libgloox.dylib @executable_path表示执行程序文件的路径,也就是说您只需要把动态库拷贝到与执行程序文件相同的路径下即可正常运行。修改后的动态库连接路径如下(图3) 图3 修改动态库连接路径 四、使用gloox 在gloox源代码目录src/example中有很多的使用示例,可以直接运行查看其效果。 这部分目前正在研究中,详细的用法且听下回分解。 liwei tag:www.nibirutech.com,2008-09-23:62 2008-09-23T01:20:00Z 2008-09-23T01:22:33Z UITabBarController 的使用 UITabBarController 的使用: viewController 是什么呢? 首先不得不提MVC , 这里viewController的作用就是Controller。viewController 控制view,并提供数据给view。 比如:常常用一个viewController 来做tableView的delegate,来提供数据给tableView。这个tableView 可以包含在viewController中(把tableView加到viewController 的view 中),也可以在viewController之外。 iphone SDK 提供了四个默认的viewController:UITabBarController,UITableViewController ,UINavigationController ,UIImagePickerController 。其中 UIImagePickerController 是UINavigationController的子类。 UITabBarController 包含一个tabbar,及一个view,可以用来控制数个viewController,包括UINavigationController 。tabbar由tabbarItem 组成,每一个tabbarItem 都包含image 等属性。当把viewControllers 加入到UITabBarController 中时,每个viewController会自动对应到UITabBarController 的tabbar 的一个tabbarItem 。viewController 的title 会自动显示在tabbarItem中,要给viewController配的icon 直接加到tabbarItem 的image 属性即可。注意这里的icon 除了你想显示的部分,其它必须是透明的。使用UITabBarController的好处除了保持界面的一致性外,另一个很大的好处是它会自动帮你管理viewControllers,你不用设置tabbarItem的动作,便可以切换viewControllers。不错吧。但UITabBarController的不足是tabbar的高度不能设置,更确切的说是它没有提供它的tabbar的操作给我们。太斯托拉了。另外UITabBarController 最多只能显示5个tabbarItems。当多于这个数字时,会自动加一个more item。用来切换进另外一个界面。这个界面上显示了多于的tabbarItems ,只不过是用table 格式来显示的。此时用户可以编辑显示的tabbarItems(增删)及 它们的显示顺序。 有人可能回想我还不如用toolbar呢,这时你就得自己动手代码控制界面切换了。而且如果要实现UITabBarController的效果,避免不了曲线救国。 总的来说UITabBarController还是不错的,大家可以试一下。 xuzepei tag:www.nibirutech.com,2008-09-23:61 2008-09-23T00:29:00Z 2008-09-24T02:25:10Z Mac 桌面应用软件开发经验小结 &lt;!--[if IE]> &lt;?XML:NAMESPACE PREFIX = GDOC /> &lt;![endif]--> <div>&nbsp;</div> <div>1. User Defaults</div> <div>&nbsp;</div> <div>1.1 功能:可用作保存程序的用户界面的习惯设置等,相当于windows平台下的ini文件</div> <div>&nbsp;</div> <div>1.2 基本用法:</div> <div>step1 : 注册key并附初值</div> <div>&nbsp;</div> <div>//返回默认的UserDefaults对象</div> <div>[NSUserDefaults standardUserDefaults]</div> <div>&nbsp;</div> <div>//该方法完成注册的功能</div> <div>- (void)registerDefaults:(<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/Reference/Reference.html#//apple_ref/doc/c_ref/NSDictionary">NSDictionary</a> *)<i>dictionary</i></div> <div>&nbsp;</div> <div><i>exp.</i></div> <div><i>&nbsp;&nbsp;&nbsp;&nbsp; //注册key1,并附初值为NO</i></div> <div>&nbsp;&nbsp;&nbsp;&nbsp; NSMutableDictionary *defaultValues = [NSMutableDictionary dictionary];<br> &nbsp;&nbsp;&nbsp;&nbsp; [defaultValues setObject:[NSNumber numberWithBool:NO] forKey:@"key1"];<br> &nbsp;&nbsp;&nbsp;&nbsp; [[NSUserDefaults standardUserDefaults] registerDefaults: defaultValues];</div> <div>&nbsp;</div> <div>step2:修改key值和获取key值</div> <div>&nbsp;</div> <div>//修改方法</div> <div>- (void)setObject:(id)<i>value</i> forKey:(<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/doc/c_ref/NSString">NSString</a> *)<i>defaultName</i></div> <div><i>//获取方法</i></div> <div>- (id)objectForKey:(<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/doc/c_ref/NSString">NSString</a> *)<i>defaultName</i></div> <p>&nbsp;</p> <div>&nbsp;</div> <div>step3: 删除key</div> <div>&nbsp;</div> <div>//删除用户设置的key</div> <div>- (void)removeObjectForKey:(<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/doc/c_ref/NSString">NSString</a> *)<i>defaultName</i></div> <div>&nbsp;</div> <div>1.3 注意事项:</div> <div>&nbsp;</div> <div>建立key的操作通常应该放在程序启动时,还应该判断key是否已经存在,所以这里建议在registerDefaults时,传入的dictionary应该包含类对象类型(如NSNumber*,而非BOOL),目的在于可以通过这样的方式判断key是否已经建立:</div> <div>&nbsp;</div> <div>&nbsp;if([[NSUserDefaults standardUserDefaults] objectForKey:@"key1"] == nil)<br> &nbsp;{<br> &nbsp;&nbsp;&nbsp;&nbsp; NSMutableDictionary *defaultValues = [NSMutableDictionary dictionary];<br> &nbsp;&nbsp;&nbsp;&nbsp; [defaultValues setObject:[NSNumber numberWithBool:NO] forKey:@"key1"];<br> &nbsp;&nbsp;&nbsp;&nbsp; [[NSUserDefaults standardUserDefaults] registerDefaults: defaultValues];<br> &nbsp;}</div> <div>&nbsp;</div> <div>2. window窗口和splitview窗口的resize问题</div> <div>&nbsp;</div> <div>2.1 窗口大小变化前,绝大多数会发送delegate消息(windowWillResize:toSize:),但并非所有:比如程序启动时,以及toolbar显示和缩进隐藏切换时,应当注意对这些情况的处理。</div> <div>&nbsp;</div> <div>2.2 splitview 如果设置autoresize,那么spliteview中的个部分会按当前比例放大缩小</div> <div>&nbsp;</div> <div>//该方法可以设置分割条的位置</div> <div><i>-&nbsp;(void)setPosition:(CGFloat)position ofDividerAtIndex:(NSInteger)dividerIndex</i></div> <div>&nbsp;</div> <div>2.3 在处理多子窗口resize等问题时,在interfacebuilding中应注意窗口间的包含管理,可以使用tool-&gt;select parent 查看父窗口</div> <div>&nbsp;</div> <div>&nbsp;</div> <div>3. NSPersistentStoreCoordinator,NSManagedObjectContext 和 NSManagedObjectModel</div> <div>&nbsp;</div> <div>3.1 NSPersistentStoreCoordinator 代表存储器对象,类型可以是xml,也可以是sqlite等等,根据情况选择使用,其中xml效率较低</div> <div>&nbsp;</div> <div>-&nbsp;(<a href="http://developer.apple.com/documentation/Cocoa/Reference/NSPersistentStore_Class/Reference/NSPersistentStore.html#//apple_ref/doc/c_ref/NSPersistentStore">NSPersistentStore</a> *)addPersistentStoreWithType:(<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/doc/c_ref/NSString">NSString</a> *)storeType configuration:(<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/doc/c_ref/NSString">NSString</a> *)configuration URL:(<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/Reference/Reference.html#//apple_ref/doc/c_ref/NSURL">NSURL</a> *)storeURL options:(<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/Reference/Reference.html#//apple_ref/doc/c_ref/NSDictionary">NSDictionary</a> *)options error:(<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSError_Class/Reference/Reference.html#//apple_ref/doc/c_ref/NSError">NSError</a> **)error</div> <div>&nbsp;</div> <div>参数一即为存储类型:</div> <div>NSXMLStoreType对应xml</div> <div>NSSQLiteStoreType对应sqlite</div> <div>&nbsp;</div> <div>3.2 NSManagedObjectModel 代表所用实体和他们的属性构建起的模型,NSPersistentStoreCoordinator 初始化时需要使用NSManagedObjectModel 对象</div> <div>&nbsp;</div> <div>3.3 NSManagedObjectContext&nbsp; 代表运行时Model的数据内容,和controller进行数据绑定后,可以使用save方法对controller中的数据进行保存,程序运行时能自动读取以前存储过的数据。</div> <div>&nbsp;</div> <div>//保存数据</div> <div>- (IBAction) saveAction:(id)sender {</div> <div>&nbsp;&nbsp;&nbsp; NSError *error = nil;<br> &nbsp;&nbsp;&nbsp; if (![[self managedObjectContext] save:&amp;error]) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [[NSApplication sharedApplication] presentError:error];<br> &nbsp;&nbsp;&nbsp; }<br> }</div> <div>&nbsp;</div> <div><br> </div> <div>&nbsp;</div> <div>&nbsp;</div> <div>&nbsp;</div> <div>&nbsp;</div> <div>&nbsp;</div> <div>&nbsp;</div> <div><br> &nbsp;</div> <br> klaus tag:www.nibirutech.com,2008-09-19:60 2008-09-19T01:39:00Z 2008-09-19T02:30:45Z Scrum Template We use Scrum to manage the software development procedure, and we will send daily scrum report to all related people. You may check the daily scrum report template here: &lt;font><p>Hi, all<br /> This is the report for EC project on Sep. 3, 2008. <br /> Burn Down Chart:</p> <p><img src="/assets/2008/9/19/daily_scrum_report_template.png" height="280px" width="600px" /></p> <p>Impediment List: <br /> no <br /> <br /> Daily Meeting: <br /> mike: yesterday: task1 <br /> today: task2 <br /> difficult: no <br /> john: yesterday: task3 and task4 <br /> today: task5 <br /> difficult: no <br /> andy: yesterday: no task done <br /> today: task6 <br /> difficult: no <br /> Kind Regards <br /> </p>&lt;/font> <p>After each sprint, usually 2 weeks, we will make a sprint meeting to check the demo, to report code review, and to draft next sprint tasks, and would make a report like this: <br /> &lt;font>Hi all,<br /> The EC team has finished sprint 1 on time, this morning we held a scrum meeting to report sprint 1 situation, and made plan for sprint 2.<br /> Sprint 1:<br /> Burn Down Chart:<br /> <img src="/assets/2008/9/19/sprint_1.png" height="280px" width="600px" /><br /> Working days: 11<br /> Story Points: 13 Extra Points: 2<br /> Total Points: 15 avg. Team Speed: 1.36<br /> Code Review: yes, Bugs: 6, Fixed: 6;<br /> Documentation: yes;<br /> Refactor: yes;<br /> Demo: yes, Bugs: 3, Fixed:3<br /> Sprint 2:<br /> Burn Down Chart:<br /> <img src="/assets/2008/9/19/pub.png" height="280px" width="600px" /><br /><br /> Estimated working days: 12<br /> Story Points: 16 Extra Points: 2<br /> Total Points: 18 avg. Team Speed: 1.5<br /> Impediment List:<br /> unfixed team speed<br /> Kind Regards </p>&lt;/font> <p>Also we would create a code review report to help beautify the code and improve the quality.</p> klaus tag:www.nibirutech.com,2008-09-01:59 2008-09-01T08:05:00Z 2008-09-01T08:07:53Z Post your Project <p>For a better understanding of the project, we invite you to fill a form here: <br>&lt;iframe src="http://spreadsheets.google.com/embeddedform?key=pjXnIXAQnRJ3-d8Ccib9MXw" height="2500" width="700">Loading...&lt;/iframe> </p> klaus tag:www.nibirutech.com,2008-09-01:58 2008-09-01T07:41:00Z 2008-09-01T07:43:31Z Programming Guide &lt;style> table { font-size: 1em; line-height: inherit; } tr { text-align: left; } /* 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; } &lt;/style> <div> <span>&lt;font>Ruby on Rails Programming Guide in NibiruTech&lt;/font></span> </div> <div> <br> </div> <div> <span><span>&lt;font>&nbsp;&nbsp; &nbsp;&lt;/font></span><span>1. Coding Standard</span><span><span>&nbsp;</span><span>&nbsp;&nbsp; &nbsp;</span></span></span> </div> <div> <span>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;comment</span> </div> <div> <span>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;1.1 There should be Description to Module or Class above of them</span> </div> <div> <span>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;1.2 There should be Description to method above of it</span> </div> <div> <span>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;1.3 Format of comment</span> </div> <div> <span>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Begins with a '#', followed by one blank space, capitalize the first letter, and end with '.' . There should be a <b>comment</b>&nbsp;<b>row</b> after each comment sentence, like the following sample:</span> </div> <div> <br> </div> <blockquote> # This is a comment sample, this comment sentence is not over yet,<br> <div> # now this comment sentence is over. </div> <div> # </div> <div> # Above is the&nbsp;<b>comment&nbsp;</b><b>row</b>, after a comment sentence. </div> <div> # </div> <div> # ........ </div> </blockquote> <div> <span>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;1.4 Declare the copyright by adding writer's Name and E-mail Address</span><span>, like:</span> </div> <div> <span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> </div> <br> <blockquote> # ProductsController<br> #<br> # Language: &nbsp; &nbsp;Ruby on Rails<br> #<br> # Maintainer:&nbsp;&nbsp;&nbsp; &nbsp;Tom &lt;sunkunjian@nibirutech.com&gt;<br> #&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Neil &lt;lvjiajun@nibirutech.com&gt;<br> #&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Joey &lt;joey@nibirutech.com&gt; &nbsp; &nbsp; &nbsp;&nbsp; </blockquote> <div> <span>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;1.5 When some lines of code need to be annotated specially, should annotate above those codes</span> </div> <div> <span> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;1.6 All comments in code should be written in English </span> </div> <div> <span> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;1.7 Use proper words( No fuck, shit) </span> </div> <div> <span> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;1.8 Put on line comment for even simple methods</span> </div> <div> <span> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;1.9 Put enough comments for complex methods</span> </div> <div> <br> </div> <div> <span>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Format of Codes</span> </div> <div> <span> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;1.10 Constant</span> </div> <div> <span>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; All Letters in CAPITALIZATION, and use &lt;u>Underline&lt;/u> to link words like:</span> </div> <blockquote> TIMEZONE_OPTIONS = [<br> <div> &nbsp;&nbsp;["Newfoundland Daylight Time / NDT-514", "514"] </div> <div> ]&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; </div> </blockquote> <div> <span> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;1.11 Naming Rule </span> </div> <div> <span> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Always try to avoid meaningless variable name. variable name should describe its function, like: </span> </div> <blockquote> <div> Array.new(size) { |index| block } </div> <div> Array.new(length) { |index| block } </div> </blockquote> <div> &lt;font>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;/font><span>Use size or length t</span><span>o&nbsp;</span><span><span>express Array size or length, use index to express Array index.</span></span> </div> <div> <span> &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp;frequently-used variable name </span> </div> <div> <span> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;height, width, length, size, index, max, min, num, str, arr, name, age, hash, key, value </span> </div> <div> <br> </div> <div> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </div> <div> <span> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;1.12 Format of Coding </span> </div> <div> <span>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; indent 2 characters like: </span> </div> <blockquote> if y &gt; 0<br> <div> &nbsp;&nbsp;p "y &gt; 0" </div> <div> &nbsp;&nbsp;y = 0 </div> <div> end </div> </blockquote> <div> <span>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;dyadic operator</span> </div> <blockquote> Correct: &nbsp; :a =&gt; "a"<br> False &nbsp; : &nbsp; :a=&gt;"a" </blockquote> <div> <br> </div> <div> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span>when multi parameters, use comma follow the previous parameter closely, and leave one blank space before next parameter, like: </span> </div> <blockquote> Correct: &nbsp; method_one(arg_one, arg_two, arg_three)<br> <div> False &nbsp; : &nbsp; method_two(arg_one,arg_two,arg_three)&nbsp; </div> </blockquote> <div> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span>Leave a row between Classes, Modules and Methods, like: </span> </div> <blockquote> class Foo<br> <div> &nbsp;&nbsp;def method_one </div> <div> &nbsp;&nbsp; &nbsp;...... </div> <div> &nbsp;&nbsp;end </div> <div> &nbsp;&nbsp; &nbsp; &nbsp; </div> <div> &nbsp;&nbsp;def method_two </div> <div> &nbsp;&nbsp; &nbsp;...... </div> <div> &nbsp;&nbsp;end </div> <div> end </div> <div> &nbsp;&nbsp; &nbsp; </div> <div> class Bar </div> <div> &nbsp;&nbsp;... </div> <div> end &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </div> </blockquote> <div> <br> </div> <div> <span> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; When code (Hashes, Arrays) is too long, wrap new lines, make alignment to&nbsp;operational character, like:</span> </div> <blockquote> hash = {&nbsp;<br> <div> &nbsp;&nbsp;:name &nbsp; =&gt; "kevin",&nbsp; </div> <div> &nbsp;&nbsp;:age &nbsp; &nbsp; &nbsp;=&gt; 26,&nbsp; </div> <div> &nbsp;&nbsp;:gender =&gt; "male",&nbsp; </div> <div> } </div> </blockquote> <div> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span>When defining methods encountering too many parameters, (please try to avoid this situation) like:</span> </div> <div> <br> </div> <blockquote> def method( foo, bar, foo1, bar1, \<br> <div> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; foo2, bar2, ) </div> <div> &nbsp;&nbsp;......&nbsp; </div> <div> end </div> </blockquote> <div> &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; <span>Insert blank space after "&lt;%=" and "&lt;%", and before "%&gt;" and "-%&gt;", like:</span> </div> <div> <br> </div> <blockquote> &lt;%= h product.title %&gt;<br> <div> &lt;% print "hello world!" %&gt;&nbsp;&nbsp;&nbsp; </div> </blockquote> <div> <span> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Where to show text, use&nbsp;</span><span><span>specific codes to filter forbidden characters, like:</span></span> </div> <blockquote> &lt;%= h content %&gt; or escape_javascript(javascript) </blockquote> <div> <br> </div> <div> <span> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Sql statement</span> </div> <blockquote> &lt;font> find :all, &nbsp; :conditions =&gt; { :fielda =&gt; valuea,&nbsp;&lt;/font><span>&lt;font>:fieldb =&gt; [...], :fieldc =&gt; value&lt;/font>&lt;font>c ...}&lt;/font></span><span>&lt;font>&nbsp;#safe<br> &lt;/font> <span>&lt;font>find :all, &nbsp; :conditions =&gt; ["fielda=? and fieldb=?",valuea,valueb]&lt;/font></span><span>&lt;font>&nbsp;#safe&lt;/font></span>&lt;font>&nbsp;<br> &lt;/font> <span>&lt;font>find :first, :conditions =&gt;&nbsp;"user_name = '#{user_name}'") #dangerous&lt;/font></span>&lt;font>&nbsp;<br> &lt;/font> <span>&lt;font>find :first, :conditions =&gt; ["user_name = ?", user_name]) #safe&lt;/font></span>&lt;font>&nbsp;<br> &lt;/font> <div> <span><span><span><span><span>&lt;font>find :first, :conditions =&gt; {:user_name =&gt; user_name}) #safe&lt;/font></span><span>&lt;font>&nbsp;&nbsp;&lt;/font></span>&lt;font>&nbsp; &nbsp;&lt;/font>&lt;font>&lt;font>&nbsp;&nbsp; &nbsp; &lt;/font>&nbsp;&nbsp;&lt;/font></span></span></span></span> </div> </span> </blockquote> <div> <span>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; No print statements in Codes (unless necessary)</span> </div> <div> <br> </div> <div> <span>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; method and parameter names should in lower case and underline; capitalize first letter of Module name.</span> </div> <div> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;method: get_data </div> <div> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;parameter: validate_birthday </div> <div> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Module: &nbsp; &nbsp;ProductsApplication </div> <div> <br> </div> <div> <span>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; 1.13 Documentation after each iteration</span> </div> <div> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; </div> <div> &lt;font>&nbsp;&nbsp; &nbsp;&lt;/font><span>2. Which code is better&nbsp;</span> </div> <div> <span>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;2.1 Use symbol as key in hash, like</span> </div> <blockquote> Better:&nbsp;&nbsp; &nbsp;h = { :name =&gt; "Kevin", &nbsp;:age =&gt; 26 }<br> <div> Worse:&nbsp;&nbsp; &nbsp;h = { "name" =&gt; "Kevin", "age" =&gt; 26 }&nbsp; </div> </blockquote> <div> <span>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;2.2 Try to use "each", "map", "collection", "reject", "inject" statements, instead of "for", "while" statements, like:</span> </div> <blockquote> arr = [ 1, 2, 3, 4, 5] </blockquote> <div> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span>Worse:&nbsp; </span> </div> <blockquote> sum = 0<br> <div> for num in arr </div> <div> &nbsp;&nbsp;sum += num </div> <div> end </div> </blockquote> <div> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span>Better:</span> </div> <blockquote> sum = 0<br> <div> arr.each { |num| sum += num } </div> </blockquote> <div> <span>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Cool:</span> </div> <blockquote> arr.inject { |sum, num| sum += num } </blockquote> <div> </div> <div> <span><span>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<span><span>&nbsp;&nbsp; &nbsp;<span><span>&nbsp;&nbsp; &nbsp;<span>or</span></span></span></span></span></span></span> </div> <blockquote> arr.inject(0) { |sum, num| sum += num } </blockquote> <div> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span>&nbsp;</span> </div> <div> <span>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;2.3&nbsp;</span> </div> <div> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span>Better:</span> &nbsp;&nbsp; </div> <blockquote> @session[:user_id] ||= user.id&nbsp; </blockquote> <div> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span>Worse:</span> &nbsp;&nbsp; </div> <blockquote> @session[:user_id] = user.id </blockquote> <div> <span>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span> </div> <div> <span>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;2.4 Try to put logic into models instead of into controllers</span> </div> <div> <span>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Put common methods into ApplicationController instead of into single controller</span> </div> <div> <span>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Put View's logic into helpers</span> </div> <div> <br> </div> <div> <span>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; 2.5 when using logical&nbsp;<span><span>operational character, be aware of priority, see</span></span></span> </div> <blockquote> !( a &amp;&amp; b),&nbsp; </blockquote> <div> <br> </div> <div> <br> </div> <div> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; 2.6&nbsp;<span>Naming method, the first word would express its function</span>, add_column, find_gender_by_name..... </div> <br>