天天看點

【黑馬程式員】Objective-C語言學習筆記之核心文法(四)

--------------------------------------------IOS期待與您交流!--------------------------------------------

一、點文法

1、沒有使用點文法的情況

此時我們使用setter和getter方法來通路對象的成員變量
#import <Foundation/Foundation.h>

@interface Person : NSObject
{
    int _age;
}
- (void)setAge:(int)age;
- (int)age;
@end

@implementation Person

- (void)setAge:(int)age
{
    NSLog(@"調用了setAge方法");
    _age = age;
}

- (int)age
{
    NSLog(@"調用了age方法");
    return _age;
}
@end

int main()
{
    // 沒有使用點文法的時候
    Person *p = [Person new];
    [p setAge:20];
    int age = [p age];
    NSLog(@"年齡是:%d", age);
    return 0;
}
           

輸出結果:

2014-03-19 20:15:13.476 Test[470:303]調用了setAge方法

2014-03-19 20:15:13.477 Test[470:303]調用了age方法

2014-03-19 20:15:13.478 Test[470:303]年齡是:20

2、使用了點文法的情況

使代碼更簡潔了, 本質是方法調用
#import <Foundation/Foundation.h>

// Person方法的聲明和實作和上面一樣

int main()
{
    // 使用點文法的時候
    Person *p = [Person new];
    p.age = 20; // 本質是 -> [p setAge:20];
    int age = p.age; // 本質是 -> int age = [p age];
    NSLog(@"年齡是:%d", age);
    return 0;
}
           

輸出結果:

2014-03-19 20:15:13.476 Test[470:303] 調用了setAge方法

2014-03-19 20:15:13.477 Test[470:303] 調用了age方法

2014-03-19 20:15:13.478 Test[470:303] 年齡是:20

3、注意

- (void)setAge:(int)age
{
    // 相當于 [self setAge:age],會引發死循環
    self.age = age;
}

- (int)age
{
    // 相當于 [self age],會引發死循環
    return self.age;
}
           

二、成員變量的作用域

public:在任何地方都能直接通路對象的成員變量

protected:可在目前類及其子類對象中直接通路對象的成員變量(預設的)

private:隻能在目前類中直接通路對象的成員變量

package:同一架構中能直接通路對象的成員變量

三、@property和@synthesize

1、以前的代碼方式

@interface Person : NSObject
{
    int _age;
}
- (void)setAge:(int)age;
- (int)age;
@end

@implementation Person

- (void)setAge:(int)age
{
    _age = age;
}

- (int)age
{
    return _age;
}
@end
           

2、使用了@property和@synthesize

下面代碼和上面是等效的
@interface Person : NSObject
@property int age;
@end

@implementation Person
@synthesize age = _age;
@end
           

3、隻使用了@property

下面代碼和上面是等效的
@interface Person : NSObject
@property int age;
@end

@implementation Person
@end
           

4、總結

1-> 隻用@property時,會産生3個效果(以@property int 為例)

    1 生成 _age 成員變量(private的成員變量)

    2 生成 age 的 setter 和 getter 方法的聲明

    3 生成 age 的 setter 和 getter 方法的聲明

2-> 使用@property和@synthesize時,和上面的效果基本相同,不同在于@synthesize可以指定生成的成員變量的名稱。

@interface Person : NSObject
@property int age;
@end

@implementation Person
@synthesize age = hello;
@end
           
就會等價于
@interface Person : NSObject
{
    int hello;
}
- (void)setAge:(int)age;
- (int)age;
@end

@implementation Person

- (void)setAge:(int)age
{
    hello = age;
}

- (int)age
{
    return hello;
}
@end
           
使用@synthesize時,推薦使用_age,這樣更符合約定

5、此外

隻有使用了@property ,才會自動生成private的_age。使用@synthesize 用來改變@property 生成的成員變量名。

如果自己隻實作了setter 方法,會自動生成getter 方法和帶下劃線的成員變量(_age)

如果自己隻實作了getter 方法,會自動生成setter 方法和帶下劃線的成員變量(_age)

如果自己實作了setter 方法和getter 方法,就不會自動生成成員變量(_age),需要我們手動生成

四、構造方法(init)

1、new方法

我們可以通過new 方法來生成一個對象
Person *p = [Person new];
           

其實new 是分兩步來生成對象的

* 調用+alloc 方法來給對象配置設定記憶體空間

* 調用-init 方法給對象的成員變量初始化成預設的值

缺點:不能在建立對象的同時進行一些必要的初始化

2、alloc 和 init 方法

重寫構造方法的目的:為了讓對象一建立出來,成員變量就由一些預設的值
@interface Person : NSObject
@property int age;
@end

@implementation Person
// 需要重寫init 方法來滿足自己的初始化要求
- (id)init
{
    // 必須先調用父類的構造方法對父類的變量進行初始化
    if (self = [super init]) {
        _age = 20;
    }
    return self;
}
@end

int main()
{
    Person *p = [[Person alloc] init];  // 和 Person *p = [Person new]; 一樣的效果
    NSLog(@"年齡是:%d", p.age);
    return 0;
}
           

輸出:

2014-03-19 21:20:29.860 Test[644:303]年齡是:20

3、自定義init 方法(自定義構造方法)

@interface Person : NSObject
@property int age;
@end

@implementation Person
- (id)initWithAge:(int)age
{
    if (self = [super init]) {
        _age = age;
    }
    return self;
}
@end

            
int main()
{
    Person *p = [[Person alloc] initWithAge:24];  
    NSLog(@"年齡是:%d", p.age);
    return 0;
}
           
輸出: 2014-03-19 21:25:55.821 Test[656:303]年齡是:24

五、分類(Category)

作用:在不改變類的基礎上增加一些方法

類名:類名 (分類名)

分類名一般是子產品名

如想為Person類增加一個添加一個分類LXZ

Person+LXZ.h

#import "Person.h"

@interface Person (LXZ)
- (void)study;
@end
           
Person+LXZ.m
#import "Person+LXZ.h"

@implementation Person (LXZ)
- (void)study
{
    NSLog(@"lxz study");
}
@end
           
main.m
#import <Foundation/Foundation.h>
#import "Person.h"
#import "Person+LXZ.h"

int main()
{
    Person *p = [[Person alloc] init];  
    [p study];
    return 0;
}
           

輸出:

2014-03-19 21:58:17.997 OCTest[841:303] lxz study

注意

 1 分類隻能增加方法,不能增加成員變量

 2 分類方法中可以通路原來類中的成員變量

 3 分類可以重新實作原來類中得方法,這會覆寫原來類中的方法,使原來類中的方法失效

 4 方法調用優先級:分類(最後被編譯的分類) -> 原來類

六、SEL

在OC中,對象或類每當調用一個方法時,會把方法包裝成一個SEL的資料類型,然後去類對象中找對應的SEL(類對象中有該類的所有方法的SEL,每個方法對應一個SEL)。若找到,則調用相應的方法,若沒找到,則報錯。

以上面的 Person 類為例,看看調用age的getter方法的方式有哪些

方式一(隐式的使用了SEL)

[p age];
           
方式二(顯式的使用了SEL)
[p performSelector:@selector(age)];
           
方式三(顯示的使用了SEL)
SEL sel = NSSelectorFromString(@"age");
[p performSelector:sel];
           

--------------------------------------------IOS期待與您交流!--------------------------------------------

詳細請檢視:http://edu.csdn.net