天天看点

【黑马程序员】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