Objective-C 學習筆記 (2) - 方法

Objective-C method

方法的呼叫與定義。
前一篇有提到,方法的定義及呼叫方式,但沒提及參數,如果方法中要傳遞參數的話要這麼寫:
//宣告
- (void) setSizeWidth:(int)w andHeight:(int)h { //... }

//呼叫(傳遞訊息)
[obj setSizeWidth:100 andHeight:50];
類比 Java 為:
//宣告
public void setSize(int width, int height) { //... }

//呼叫
obj.setSize(100, 50);
你可以比較兩者寫法的不同。

Objective-C 看起來有點累贅,呼叫時每個參數都要寫完整的名稱,相對於 Java 只要在括號內寫要傳入的值來的冗長。它的優點在於,當這個 setSize 方法不是由你所寫時,Objective-C 可以很容易從參數名稱來看出要傳入的數值是什麼,Java 則必須查一下 API 才能確定。不過現在IDE的提示功能都很強了,所以我覺得還好,反正就是適應各自的寫法,寫久了就習慣了。

從上面的例子你可以看到 Objective-C 的方法宣告是可以很長的,而它的名稱是會以冒號 (:) 來分隔的,所以 Objective-C 方法的完整名稱為:
setSizeWidth:andHeight:
有沒有冒號差很大,如果該方法不需要傳入參數的話,就不能用到冒號,所有參數以冒號分隔,組合而成為完整的方法名稱。

方法的公開或私有

寫 Java 的人都知道 public、private、protected 等存取修飾字,可以用來限制方法或屬性的存取限制。但 Objective-C 的方法則預設都是公開的,並沒有私有方法這種東西,而屬性則會被定義成保護,在大多數情況下都能取用。

由於 Objective-C 類別的組成由 .h 及 .m 兩個檔案來完成,而 .h 是可以公開的, .m 則是不公開的,所以當你把方法定義在 .h 中,表示這些方法可以讓其他類別來使用,等同於 public ;而當你把方法寫在 .m 中,則因為只有該類別自己知道,所以就等同於 private 了。屬性也是同樣的概念。

接下來是完整範例示範:

Car.h

#import <Foundation/Foundation.h>

@interface Car : NSObject
{
    //屬性
    NSString *color;
    int price;
}

//setter, getter
- (NSString*)color; //getter
- (void)setColor:(NSString *)color; //setter

- (int)price;
- (void)setPrice:(int)price;

//init method
- (id)init;

//method
- (void)move;

@end

Car.m

#import "Car.h"

@interface Car()
{
    int numberOfMiles;
}

@end

@implementation Car
- (id)init
{
    if (self = [super init]) {
        [self setSizeWidth:100 andHeight:50];
        numberOfMiles = 100;
    }
   
    return self;
}

//setter ,getter
- (NSString*)color
{
    return color;
}
- (void)setColor:(NSString *)theColor
{
    color = theColor;
}

- (int)price
{
    return price;
}
- (void)setPrice:(int)thePrice
{
    price = thePrice;
}


//method
- (void)move
{
    numberOfMiles++;
    NSLog(@"moved miles: %d", numberOfMiles);
}

//private method
- (void)setSizeWidth:(int)width andHeight:(int)height
{
    NSLog(@"widht: %d and height: %d", width, height);
}

@end
解說:
先看 Car.h
#import <Foundation/Foundation.h>
在 C 語言中,會使用 #include 來載入需要使用的函式庫,Objective-C 也可以使用,但建議使用 #import ,兩者功能一樣,但 #import 不會重覆載入,所以大都使用 #import 。

Foundation 是 Objective-C 的基礎類別庫,包含如 NSObject、NSString 等的常用類別,所以是一定要 import 的。

為了讓屬性可以存取,所以會有存取子 setter (設定)及 getter (取值)的方法,之後會介紹使用 @property 來自動建立,而不需手動撰寫。這裡要注意,因為 color 的資料型態是 NSString *,所以回傳值也必須為 (NSString *) 。

這時你也會注意到 getter 的方法名稱竟然和屬性同名,這在 Objective-C 中是被允許的,所以屬性名稱和方法名稱可以一樣。而 getter 通常也都是和屬性同名,不會像 Java 寫成 getColor ,setter 則會以屬性名稱的前面加上 set 並且把首字母大寫來表示,例如 setColor: 。

這個例子我們建立了一個初始化方法 init ,它的回傳值很特別,叫做 id ,初始化方法回傳值一律為 id 。什麼是 id 呢?那就是它什麼都是,它是萬物,你指定給個 id 變數 NSString 它就是 NSString;指定為 NSArray 它就是 NSArray ,端看你指定給它什麼資料型態而定。

接著來看 Car.m
首先它 #import "Car.h" 進來,這是必須的,因為要使用 .h 中所定義的介面,所以必須 import 進來,而因為在 .h 中有 import Foundation.h 所以在 Car.m 中就不需在重覆 import 。

接下來你會看到
@interface Car()
{
    int numberOfMiles;
}
@end
這段程式碼是非必須的,當你有需要使用到變數,而這個變數只會在 .m 中使用,不想對外公開,而且是整個類別中都能存取,這時就可以寫在 .m 的 interface 區塊。這裡的 interface 和 .h 中寫法略有不同,類別名稱後面直接接括號,而不是繼承,這裡要注意。

一般來說,如果沒有 @interface 區塊,那最開始的就會是 @implementation ,在 implementation 之下全都是 .h 中方法的實作。這些方法名稱必須和 .h 中定義的相同,只是原本結尾為的分號換成大括號,並且在其中實作程式邏輯。

首先是初始化方法,這是標準寫法:
- (id)init
{
    if (self = [super init]) {
        //要初始化資料的地方
    }
   
    return self;
}
初始化一定要從父類別先開始,所以會先使用 [super init] 呼叫父類別的初始化方法。
初始化方法可以有很多個,但都會以 init 起頭,例如:
- (id)initWithTitle:(NSString*)title;
- (id)initWithTitle:(NSString*)title number:(int)number description:(NSString*)desc;
這些初始化方法可同時存在,其他類別則依需求呼叫其中一個初始化方法。

存取子 setter, getter 沒什麼特別,就是設定屬性資料及取得屬性值而以,因為這些程序太過單純,所以之後可以用 @property 來自動產生,就不需每個屬性都去寫了。

接下來會看到兩個方法的實作,move 這是公開的,因為在 .h 中有宣告,所以其他類別能夠看到並呼叫;而 setSizeWidth:andHeight: 則不行,因為它在 .h 中沒有宣告,但是,如果你硬去呼叫,只會在編譯時發出警告,實際上還是會呼叫成功(這部份是直接做實驗的結果,目前還不瞭解它的原理)。

資料的輸出

NSLog(@""); 是用來將資料輸出在 output 視窗中,可用來檢視執行結果,除錯時經常需要用到。在雙引號前面的 @ 是表示這個字串是 NSString 字串,因為在 Objective-C 中可以使用 C 語言的字串,為了區別,所以凡是 Objective-C 的 NSString 字串,在雙引號前面一律加上 @。

NSLog 可以格式化輸出,所以可以這麼寫:
int num = 1;
NSString *name = @"Tony";
NSLog(@"This is number %d. Your name is %@.", num, name);
//輸出結果 This is number 1. Your name is Tony.
它是用填空的方式把字串先寫好,把要填資料的部份用 %d, %@ 等符號來佔住位置,之後把要填入的資料依序放在後面並以逗號隔開。所以這邊的 num 資料就會填入 %d , name 資料則會填入 %@。

其他可用的格式化說明可參考:
http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/Strings/Articles/formatSpecifiers.html

這裡提供最常用的:
  • 字串:%@
  • 整數:%d
  • 小數:%f
其他的有需要在去查即可。
本文網址:http://blog.tonycube.com/2013/01/objective-c-2.html
Tony Blog 撰寫,轉載時請註明出處及文章連結,謝謝 😀

我要留言

留言小提醒:
1.回覆時間通常在晚上,如果太忙可能要等幾天。
2.請先瀏覽一下其他人的留言,也許有人問過同樣的問題。
3.程式碼請先將它編碼後再貼上。(線上編碼:http://bit.ly/1DL6yog)
4.文字請加上標點符號及斷行,難以閱讀者恕難回覆。
5.感謝您的留言,您的問題也可能幫助到其他有相同問題的人。