在Objective-C裡,很多類別常常有唯讀版與可變版,譬如NSString與NSMutableString、NSArray與NSMutableArray、NSDictionary與NSMutableDictionary,一般來說,唯讀版的物件建立之後就不能改變,可變版的物件建立後,可以隨心所欲地進行修改。
一旦建立出NSString物件,NSString類別並沒有提供任何方法讓我們修改其中的字串,但要小心,裡頭的字串還是有可能會改變的,以底下範例說明。
假設有個Person類別,有兩個屬性name(名字)與address(住址)。其中name屬性使用retain,address使用copy,也就是說,當你指定一個NSString物件給name時,它只會記住該物件指標並增加參考計數,而指定一個NSString物件給address時,它會傳送copy訊息給該物件,得到一份拷貝。
// Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
NSString *name;
NSString *address;
}
@property (nonatomic, retain) NSString *name;
@property (nonatomic, copy) NSString *address;
@end
// Person.m
#import "Person.h"
@implementation Person
@synthesize name;
@synthesize address;
-(NSString *)description
{
return [NSString stringWithFormat:@"name(%@), address(%@)", name, address];
}
@end
// main.m
#import <Foundation/Foundation.h>
#import "Person.h"
int main (int argc, const char * argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableString *sname = [NSMutableString stringWithString:@"Amanda"];
NSMutableString *aname = [NSMutableString stringWithString:@"Taiwan"];
Person *person = [[Person alloc] init];
person.name = sname;
person.address = aname;
NSLog(@"1: person=%@", person);
[sname appendString:@"XXX"];
[aname appendString:@"YYY"];
NSLog(@"2: person=%@", person);
[person release];
[pool release];
return 0;
}
首先建立兩個NSMutableString物件sname與aname,分別指定給person物件的name與address,然後印出person物件。接下來以NSMutableString介面修改sname與aname,然後再印出person物件,你會發現,person的name變了,address沒變。
程式輸出如下:
2012-04-14 23:01:47.603 TestNSString[24655:903] 1: person=name(Amanda), address(Taiwan)
2012-04-14 23:01:47.606 TestNSString[24655:903] 2: person=name(AmandaXXX), address(Taiwan)
結論,不要以為的物件的類別為NSString就不會改變,若要確保不變,屬性可使用copy宣告。
Raise your cup, say cheers to the moon, look down on the ground, the shadow is also drinking with me. I'm not a lonely drinker.
2012/04/14
2012/04/09
[廣告] iOS SDK 開發範例大全(The iOS 5 Developer's Cookbook: Core Concepts and Essential Recipes for iOS Programmers, 3/e)
嗨,我翻譯了一本書,在這裡打打廣告。
書名:iOS SDK 開發範例大全
原書名:The iOS 5 Developer's Cookbook: Core Concepts and Essential Recipes for iOS Programmers, 3/E
作者:Erica Sadun
譯者:我
出版社:悅知
頁數:864
這本是iOS(iPhone、iPod touch、iPad)軟體開發的入門書,更新到iOS 5、Xcode 4.2、Objective-C 2.0與block與ARC(automatic reference counting),也有講解Interface Builder(已經整合進Xcode)的新玩意兒storyboard,範例很多,內容涵蓋UI介面設計、各種視覺元件、文字標籤、表格、畫面轉換的過場動畫、自製控制項、記憶體管理、資料儲存、App Store上架、多點觸控、手勢、臉部辨識、裝置規格設定、查詢網路連線狀態與非同步下載、等等等等,極為豐富。
我在翻譯時,還發生一件事情。我拿到原文書後,發現裡面有很多地方缺失漏掉了,但不是作者的錯,應該是出版社進行編輯排版時發生錯誤,這讓我很驚訝,原文書出版社Addison-Wesley,是我心中覺得不錯的出版社,居然也會搞這種烏龍。後來更正後,也把之前印錯的書通通回收,重新出版,嗯,處理的還不錯。
關於iOS的入門書有很多,原文書中另外一本有名的是"探索 iPhone 4 程式開發實戰"(Beginning iPhone 4 Development: Exploring the iOS SDK),已經有iOS 5的版本(Beginning iOS 5 Development: Exploring the iOS SDK),但中文翻譯還沒出。
(2012.06.23更新:Beginning iOS 5 Development: Exploring the iOS SDK的繁體中文翻譯本已經出版了,書名是"探索 iOS 5 程式開發實戰")
相關連結:
1. 悅知網站關於此書的介紹。
2. 天瓏書局。
3. 博客來、金石堂、TAAZE讀冊生活。
4. Amazon(原文書)。
關於其他學習Objective-C的iOS的資源,可以參考我寫的這篇。
書名:iOS SDK 開發範例大全
原書名:The iOS 5 Developer's Cookbook: Core Concepts and Essential Recipes for iOS Programmers, 3/E
作者:Erica Sadun
譯者:我
出版社:悅知
頁數:864
這本是iOS(iPhone、iPod touch、iPad)軟體開發的入門書,更新到iOS 5、Xcode 4.2、Objective-C 2.0與block與ARC(automatic reference counting),也有講解Interface Builder(已經整合進Xcode)的新玩意兒storyboard,範例很多,內容涵蓋UI介面設計、各種視覺元件、文字標籤、表格、畫面轉換的過場動畫、自製控制項、記憶體管理、資料儲存、App Store上架、多點觸控、手勢、臉部辨識、裝置規格設定、查詢網路連線狀態與非同步下載、等等等等,極為豐富。
我在翻譯時,還發生一件事情。我拿到原文書後,發現裡面有很多地方缺失漏掉了,但不是作者的錯,應該是出版社進行編輯排版時發生錯誤,這讓我很驚訝,原文書出版社Addison-Wesley,是我心中覺得不錯的出版社,居然也會搞這種烏龍。後來更正後,也把之前印錯的書通通回收,重新出版,嗯,處理的還不錯。
關於iOS的入門書有很多,原文書中另外一本有名的是"探索 iPhone 4 程式開發實戰"(Beginning iPhone 4 Development: Exploring the iOS SDK),已經有iOS 5的版本(Beginning iOS 5 Development: Exploring the iOS SDK),
(2012.06.23更新:Beginning iOS 5 Development: Exploring the iOS SDK的繁體中文翻譯本已經出版了,書名是"探索 iOS 5 程式開發實戰")
相關連結:
1. 悅知網站關於此書的介紹。
2. 天瓏書局。
3. 博客來、金石堂、TAAZE讀冊生活。
4. Amazon(原文書)。
關於其他學習Objective-C的iOS的資源,可以參考我寫的這篇。
2012/04/05
Arduino練習:猜猜哪一個
有5個開關,一開始會隨機選出一個當做正確答案,然後讓使用者猜猜看按按看哪個才是對的,若按中正確的就點亮LED;另外有個開關是重置鍵。
接線:
從Arduino板的5V與GND接到麵包板。
Arduino腳位2、3、4、5、6、9,各接到開關的右上腳,
開關的右下腳接電阻後接地,
開關的左下腳接5V。
Arduino腳位8接電阻後接LED長腳,LED短腳接地。
程式碼如下(可到這裡下載):
/* inpin1到inpin5,讓使用者猜猜哪個才是正確的 */
int inpin1=2;
int inpin2=3;
int inpin3=4;
int inpin4=5;
int inpin5=6;
int led=8; /* LED的腳位 */
int inpinReset = 9; /* 重置 */
int randnum; /* 代表哪個才是正確答案 */
/* 重置,以亂數從新選出一個正確答案 */
/* 並熄滅LED */
void reset() {
randnum = random(1, 6);
digitalWrite(led, LOW);
Serial.print("randnum=");
Serial.println(randnum);
delay(500);
}
void setup() {
pinMode(inpin1, INPUT);
pinMode(inpin2, INPUT);
pinMode(inpin3, INPUT);
pinMode(inpin4, INPUT);
pinMode(inpin5, INPUT);
pinMode(led, OUTPUT);
pinMode(inpinReset, INPUT);
Serial.begin(115200);
reset();
}
void loop() {
/* 檢查使用者有沒有按下正確的答案(開關) */
switch (randnum) {
case 1:
if(digitalRead(inpin1) == HIGH){
digitalWrite(led, HIGH);
Serial.println("inpin1");
}
break;
case 2:
if(digitalRead(inpin2) == HIGH){
digitalWrite(led, HIGH);
Serial.println("inpin2");
}
break;
case 3:
if(digitalRead(inpin3) == HIGH){
digitalWrite(led, HIGH);
Serial.println("inpin3");
}
break;
case 4:
if(digitalRead(inpin4) == HIGH){
digitalWrite(led, HIGH);
Serial.println("inpin4");
}
break;
case 5:
if(digitalRead(inpin5) == HIGH){
digitalWrite(led, HIGH);
Serial.println("inpin5");
}
break;
}
/* 若按下inpinReset就重置 */
if(digitalRead(inpinReset) == HIGH){
Serial.println("inpinReset");
reset();
}
}
上面這份程式碼,還有很多可以改進的地方。
首先是亂數的部分,應該要先用randomSeed(analogRead(0)),才不會每次產生出來的亂數序列都是一樣的。
然後是switch的部份,可利用陣列儲存腳位,就不需要重複寫那麼多個case了。
另外,開關會有bounce問題,不過就這裡的情況來說,沒關係。
另外,可以增加「最多猜三次」這樣的行為,三次都猜錯後就失敗、重置。
可以增加揚聲器,發出猜對、猜錯的音效。
接線:
從Arduino板的5V與GND接到麵包板。
Arduino腳位2、3、4、5、6、9,各接到開關的右上腳,
開關的右下腳接電阻後接地,
開關的左下腳接5V。
Arduino腳位8接電阻後接LED長腳,LED短腳接地。
程式碼如下(可到這裡下載):
/* inpin1到inpin5,讓使用者猜猜哪個才是正確的 */
int inpin1=2;
int inpin2=3;
int inpin3=4;
int inpin4=5;
int inpin5=6;
int led=8; /* LED的腳位 */
int inpinReset = 9; /* 重置 */
int randnum; /* 代表哪個才是正確答案 */
/* 重置,以亂數從新選出一個正確答案 */
/* 並熄滅LED */
void reset() {
randnum = random(1, 6);
digitalWrite(led, LOW);
Serial.print("randnum=");
Serial.println(randnum);
delay(500);
}
void setup() {
pinMode(inpin1, INPUT);
pinMode(inpin2, INPUT);
pinMode(inpin3, INPUT);
pinMode(inpin4, INPUT);
pinMode(inpin5, INPUT);
pinMode(led, OUTPUT);
pinMode(inpinReset, INPUT);
Serial.begin(115200);
reset();
}
void loop() {
/* 檢查使用者有沒有按下正確的答案(開關) */
switch (randnum) {
case 1:
if(digitalRead(inpin1) == HIGH){
digitalWrite(led, HIGH);
Serial.println("inpin1");
}
break;
case 2:
if(digitalRead(inpin2) == HIGH){
digitalWrite(led, HIGH);
Serial.println("inpin2");
}
break;
case 3:
if(digitalRead(inpin3) == HIGH){
digitalWrite(led, HIGH);
Serial.println("inpin3");
}
break;
case 4:
if(digitalRead(inpin4) == HIGH){
digitalWrite(led, HIGH);
Serial.println("inpin4");
}
break;
case 5:
if(digitalRead(inpin5) == HIGH){
digitalWrite(led, HIGH);
Serial.println("inpin5");
}
break;
}
/* 若按下inpinReset就重置 */
if(digitalRead(inpinReset) == HIGH){
Serial.println("inpinReset");
reset();
}
}
上面這份程式碼,還有很多可以改進的地方。
首先是亂數的部分,應該要先用randomSeed(analogRead(0)),才不會每次產生出來的亂數序列都是一樣的。
然後是switch的部份,可利用陣列儲存腳位,就不需要重複寫那麼多個case了。
另外,開關會有bounce問題,不過就這裡的情況來說,沒關係。
另外,可以增加「最多猜三次」這樣的行為,三次都猜錯後就失敗、重置。
可以增加揚聲器,發出猜對、猜錯的音效。