承接上一節
簡單介紹一下屬性的另外兩個特性:
首先,在創建make時
@property NSString *make;
默認的是讀寫形式
我們可能不希望汽車對象創建後能夠修改make、model或year,這時候我們可以在聲明屬性的時候將其聲明爲只讀屬性
方法很簡單
@property (readonly) NSString *make;
這樣就聲明完成了,之後當我們在ViewController.m文件中試圖對創建完成的myCar或者是othercar對象,試圖修改其make值的時候,
系統會報錯
屬性聲明的一般形式如下:
@property <(qualifier1,qualifier2,...)> <type> <property_name>
另外,如果我們希望實現這些屬性在外部只讀,而在內部可以讀寫。也很簡單,因爲可以在.m文件中重新聲明屬性。可以通過在Car.m文件的
@implementation語句之前增加如下代碼,添加或覆蓋類的接口定義:
@interface Car()
@property (readwrite) int year;
@property NSString *make;
@property NSString *model;
@end
Car對象會使用新的實例變量定義。注意明確指定readwrite並不是必須的,默認值是readwrite。所以上面代碼中make與model跟year是一樣的,重定義後變成內部可讀寫。
Objective-C的語法之類的就不再多說了
現在介紹故事面板
(來自書上)對於用戶來說,界面就是我們的應用程序。它是用戶與爲應用程序提供動力的功能(即邏輯和數據)之間的主要門戶。通過創建一些信息型和實用性元素,包括屏幕和這些屏幕上所顯示的內容,可以設計與實現用戶體驗。我們所設計的每個屏幕可以實現如下功能:
- 顯示信息,如CarValet應用程序中汽車對象的數量
- 支持動作,如通過觸摸按鈕創建一輛新汽車
- 請求輸入,如制定汽車的品牌
- 顯示用戶活動的結果,其方式包括更新所展示的汽車,或者切換至一個支持用戶編輯汽車的屏幕
用戶每次使用應用程序時,就像是在體驗故事。故事所關注的內容可能是生活管理(Calender應用程序);與朋友聯繫(郵件、社交應用程序等)
根據我們一開始寫的Carvalet項目,我們爲他搭建場景
到這個地方來
改成——Headline
其餘的改變:
可視化元素 | 作用 | 類名 |
---|---|---|
Total Cars | 顯示停泊的汽車總數–Car對象的數量 | UILabel |
New Car | 通過添加新的Car對象,停泊一輛車 | UIButton |
Divider | 在增加汽車和查看汽車兩塊區域間添加一條視覺分割線,不會的話下面有圖解 | UIView |
Current Car Number | 顯示當前所展示的汽車對象的索引數 | UILabel |
Car Information | 顯示當前汽車的詳情 | UILabel |
Previous | 讓泊車員瀏覽汽車,提供前一輛汽車的詳情(如果有車) | UIButton |
Next | 提供下一輛車的詳情(如果有車) | UIButton |
運行如圖:(PS:New Car一開始我弄成Label,應該是Button,上面圖截得New Car顏色應該與Previous,Next顏色一樣,這裏我就不換圖了)
好了,到目前爲止,我們的界面做出來了,但是隻有外表,內在啥也沒有,我們現在來添加的這些元素行爲
添加action和outlet
元素 | 類型 | 名稱 |
---|---|---|
Total Car標籤 | IBOutlet | totalCarsLabel |
Car NUmber標籤 | IBOutlet | CarNumberLabel |
Car Info標籤 | IBOutlet | CarInfoLabel |
New Car按鈕 | IBAction | newCar: |
Previous Car按鈕 | IBAction | previousCar: |
Next Car按鈕 | IBAction | nextCar: |
方法如圖
拉過去後會跳出,對於label選擇Connection方式爲Outlet,Name根據上表
weak表示對象的所有權,能夠幫助編譯器添加內存管理代碼。理解這些內存限定符的意義非常重要。
button也是用同樣的方法拉過去,不過跳出的對話框中要改成下圖樣式,Name根據上表
這是添加完6個元素後
你會發現在ViewController.m裏面,自動多出了點東西,那些是按鈕時間,每個按鈕如何操作都在相對應的按鈕方法裏面實現
對於內存的介紹的話本文不多介紹,想了解更多自行谷歌(在這裏推薦一個翻牆的東東,Star VPN,可以在App Store裏面下載)
在ViewController.m
@implementation ViewController {
NSMutableArray *arrayOfCars; //使用mutable array記錄所有汽車對象
NSInteger displayedCarIndex; //指定靠下位置顯示的汽車的數組索引
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
arrayOfCars = [[NSMutableArray alloc] init];//初始化汽車的數組爲空數組
displayedCarIndex = 0;//顯示創建的第一輛汽車
}
好了現在有保存新車的地方了,還需要創建它們,創建的方法是newCar:
newCar:方法
- (IBAction)newCar:(id)sender {
Car *newCar = [[Car alloc] init];//用默認值創建新的Car對象,並將其添加到數組中
[arrayOfCars addObject:newCar];//添加
NSString *totalCarText;
totalCarText = [NSString stringWithFormat:@"Total Cars: %d",[arrayOfCars count]];//基於當前的汽車數量,創建新的total Car Text字符串
self.totalCarsLabel.text = totalCarText;//更新顯示泊車員字符串
}
運行一下,點擊new Car
這裏我們會注意到,之前是999,我們只要到故事面板把他改成0就行了
加入顯示汽車行爲
顯示對象的信息是另一種常見的任務。UILabel能顯示字符串,通過界面中的text屬性,可以使用任何字體、大小以及指定顏色。當text屬性有所更改時,標籤也會更新。
使用UILabel顯示變化的信息需要4樣東西:標籤、標籤的關聯、用於顯示的字符串以及設置標籤文本的代碼。
我們已經在場景中添加好汽車的信息標籤,也已經關聯到標籤上。要添加對汽車的描述有幾種方法:一種是通過添加公共方法,另一種是使用read-only屬性和自定義的getter方法。要實現該屬性和getter方法,可以參照以下步驟:
- 在Car.h文件中,在fuelAmount的下方添加這行聲明屬性的代碼
@property (readonlu)NSString *carInfo;
- 打開Car.m文件,在initWithMake:的下方添加實現自定義getter方法的代碼
- (NSString *)carInfo {
return [NSString stringWithFormat:
@"Car Info\n Make: %@\n Model: %@\n year: %d",self.make ? self.make :@"Unknown Make",self.model ? self.model :@"Unknown Model",self.year];
}
PS 三元運算符?,不懂自行谷歌
現在,可以獲得描述汽車信息的字符串,還需要一種方法,用於更新顯示汽車數量和信息的標籤的文本內容。可以一一設置每個標籤所要更新的信息。但是,更新顯示的汽車信息這種行爲會在多個地方發生。在這種情況下,抽出相關的代碼是良好的設計方式
在newCar:方法的上端,添加displayCurrentCarInfos方法
- (void)displayCurrentCarInfo {
Car *currentCar;
currentCar = [arrayOfCars objectAtIndex:displayedCarIndex];
//對當前顯示的汽車對象進行加載。注意生產代碼應該覈對displayedCarIndex是否爲有效索引
self.CarInfoLabel.text = currentCar.carInfo;
//通過carInfo屬性獲得汽車的描述信息
NSString *carIndexText;
//更新汽車的標籤,注意將當前索引加1(數組從0開始)
carIndexText = [NSString stringWithFormat:@"Car Number: %d",displayedCarIndex +1];
self.CarNumberLabel.text = carIndexText;
}
在newCar:方法中,調用displayCurrentCarInfo
- (IBAction)newCar:(id)sender {
Car *newCar = [[Car alloc] init];//用默認值創建新的Car對象,並將其添加到數組中
[arrayOfCars addObject:newCar];//添加
NSString *totalCarText;
totalCarText = [NSString stringWithFormat:@"Total Cars: %d",[arrayOfCars count]];//基於當前的汽車數量,創建新的total Car Text字符串
[self dispalyCurrentCarInfo];
self.totalCarsLabel.text = totalCarText;//更新顯示泊車員字符串
}
運行結果
發現只有”Car Info”只有一行,這是因爲我們在創建Car Information時,只弄了一行
在故事面板中如下修改(就是拉長拉寬了)
再次運行
現在操作上一輛跟下一輛
在這裏先寫一個changeDisplayedCar(用來令車信息改變)
因爲上一輛下一輛的實質上是改變當前顯示的信息
- (void)changeDisplayedCar:(NSInteger)newIndex {
if(newIndex < 0) { //確保新的索引值是有效的索引。如果索引小於0,使值爲0
newIndex = 0;
} else if(newIndex >= [arrayOfCars count]) {//如果newIndex超出arrayOfCar的範圍,就將其設置爲最後一個
newIndex = [arrayOfCars count] - 1;
}
if (displayedCarIndex != newIndex) {//僅更新索引值有變化的視圖
displayedCarIndex = newIndex;
[self displayCurrentCarInfo];
}
}
previousCar:和nextCar:方法如下
- (IBAction)previousCar:(id)sender {
[self changeDisplayedCar:displayedCarIndex - 1];
}
- (IBAction)nextCar:(id)sender {
[self changeDisplayedCar:displayedCarIndex + 1];
}
運行結果
- (void)updateLabel:(UILabel*)theLabel
withBaseString:(NSString*)baseString
count:(NSInteger)theCount {
NSString *nexText;
nexText = [NSString stringWithFormat:@"%@: %d",baseString,theCount];
theLabel.text = nexText;
}
下面這些代碼是讓newCar和顯示車輛信息通過一個專門的更新標籤的方法來實現標籤的更新,這樣就不用每一個標籤寫一個專門的更改的方法了
- (void)displayCurrentCarInfo {
Car *currentCar;
currentCar = [arrayOfCars objectAtIndex:displayedCarIndex];
//對當前顯示的汽車對象進行加載。注意生產代碼應該覈對displayedCarIndex是否爲有效索引
self.CarInfoLabel.text = currentCar.carInfo;
//通過carInfo屬性獲得汽車的描述信息
[self updateLabel:self.CarNumberLabel withBaseString:@"Car Number" count:displayedCarIndex +1];
}
- (IBAction)newCar:(id)sender {
Car *newCar = [[Car alloc] init];//用默認值創建新的Car對象,並將其添加到數組中
[arrayOfCars addObject:newCar];//添加
[self updateLabel:self.totalCarsLabel withBaseString:@"Total Cars" count:[arrayOfCars count]];
}
今天的介紹就到這裏咯
我的另一個博客站點:Arnold-你們好啊