黑马程序员 OC语言 - 4 OC特有语法

来源:互联网 发布:微博域名可以修改吗 编辑:程序博客网 时间:2024/05/17 04:26

若排版有错误,请查看:http://pan.baidu.com/s/1sjoEGo9



第三章 OC特有语法

 

一、 点语法

点语法:本质是方法调用。

 

p.age = 10; // [p setAge:10];

int a = p.age; // [p age];

 

         - (void)setAge:(int)age

    {

     _age = age;

    //self.age =age; // [self setAge:age];会引发死循环

    }

 

    - (int)age

    {

       return _age;

     //return self.age; // [self age];会引发死循环

}

 

二、 成员变量作用域

    @public : 在任何地方都能直接访问对象的成员变量

    @private : 只能在当前类的对象方法中直接访问(@implementation中默认是@private

    @protected : 可以在当前类及其子类的对象方法中直接访问  (@interface中默认就是@protected

    @package : 只要处在同一个框架中,就能直接访问对象的成员变量

 

@interface@implementation中不能声明同名的成员变量

 

三、 @property和@synthesize

    // @synthesize自动生成agesettergetter实现,并且会访问_age这个成员变量,若没有会自动生成@private_age变量

    @synthesize age = _age;

 

// @property:可以自动生成某个成员变量的settergetter声明

         @propertyint age;

 

    两句可合并成一句:@property int age;

    若手动setter和getter,则不会自动生成setter和getter。

 

四、 id

id 万能指针,能指向、操作任何OC对象;

id == NSObject

 

     id d = [Personnew];

        [d setAge:10];

        NSLog(@"%d", [dage]);

 

五、 构造方法 -init

1.       构造方法:用来初始化对象的方法,是个对象方法,-开头

 

2.       完整地创建一个可用的对象:

 

1)     分配存储空间+alloc

2)     初始化 -init

 

Person *p = [[Person alloc] init]; // Person *p = [Person new];

 

(一)   重写构造方法

重写构造方法的目的:为了让对象创建出来,成员变量就会有一些固定的值

 

注意:

1.   先调用父类的构造方法([super init])

2.   再进行子类内部成员变量的初始化

 

    - (id)init

    {

        // 1.一定要调用回superinit方法:初始化父类中声明的一些成员变量和其他属性

        self = [super init];//当前对象self

   

        // 2.如果对象初始化成功,才有必要进行接下来的初始化

        if (self !=nil)

        { // 初始化成功

            _age = 10;

        }

   

        // 3.返回一个已经初始化完毕的对象

        return self;

}

 

            可将1、2步合并

    - (id)init

    {

        if ( self = [super init] )

        {

            _age = 10;

        }

        return self;

}

 

 

(二)   自定义构造方法

1.      规范:

1)     一定是对象方法,一定以 - 开头

2)     返回值一般是id类型

3)     方法名一般以initWith开头

4)     父类的属性交给父类方法去处理,子类方法处理子类自己的属性

 

声明

Person.h

Student.h

@interface Person : NSObject

@property NSString *name;

@property int age;

- (id)initWithName:(NSString *)name;

@end

#import "Person.h"

@interface Student : Person

@property int no;

- (id)initWithName:(NSString *)name andNo:(int)no;

@end

实现

Person.m

Student.m

@implementation Person

- (id)initWithName:(NSString *)name

{

    if ( self = [super init] )

    {

        _name = name;

    }

    return self;

}

@end

@implementation Student

- (id)initWithNo:(int)no

{

    if ( self = [super init] )

    {

        _no = no;

    }

    return self;

}

 

// 父类的属性交给父类方法去处理,子类方法处理子类自己的属性

- (id)initWithName:(NSString *)name andNo:(int)no

{

    // name传递到父类方法中进行初始化

    if ( self = [super initWithName:name])

    {

        _no = no;

    }

    return self;

}

@end

main.m

int main()

{

    Person *p = [[Person alloc] initWithName:@"Jack"];

    Student *stu = [[Student alloc] initWithName:@"Jim" andNo:10];

   

    return 0;

}

 

六、 Category分类

1.     作用

在不修改原来类的内容的基础上,给某个类扩充一些方法。

 

2.     使用方法

1)     声明

@interface 类名 (分类名称)  // @interface Person (ST)

@end

 

2)     实现

@implementation 类名 (分类名称)

@end

 

3.     使用注意

1)     分类只能增加方法,不能增加成员变量

2)     分类方法实现中可以访问原来类中声明的成员变量

3)     分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会导致原来的方法没法再使用

4)     方法调用的优先级:分类(最后参与编译的分类优先) --> 原来类  -->父类

 

七、 类的本质

1.     类也是一个对象

1)     类本身也是一个对象,是个Class类型的对象,简称类对象。

2)     类对象 == 类

3)     Class类型的定义:

typedef structobjc_class *Class;

 

a)  利用Class 创建Person类对象

b)  利用 Person类对象创建 Person类型的对象

 

2.     获取类对象的2种方式

// 利用Person这个类创建了2Person类型的对象

Person *p = [[Person alloc] init];

Person *p2 = [[Person alloc] init];

 

1)     对象方法:

Class c = [p class];

Classc2 = [p2 class];

2)     类方法:

Class c3 = [Person class];

 

3.     类对象调用类方法

Person *p3 = [c new];

 

4.     +load和+initialize

1)     当程序启动时,就会加载项目中所有的类和分类,而且加载后会调用每个类和分类的+load方法,只会调用一次。

2)     不管程序运行过程有没有用到这个类,都会调用+load加载

3)     当第一次使用某个类(如创建对象)时,就会调用当前类的+initialize方法

4)     先加载父类,再加载子类(先调用父类的+load方法,再调用子类的+load方法)

5)     先初始化父类,再初始化子类(先调用父类的+initialize方法,再调用子类的+initialize方法)

6)     一个类只会调用一次+initialize方法,先调用父类的,再调用子类的

 

八、 description方法

1.     –description

使用NSLog和%@输出某个对象时,会调用对象的-description方法,并拿到返回值(“类名+内存地址”)进行输出,结果是:<类名: 内存地址>

 

    Person *p =[[Person alloc] init];

   

    NSLog(@"%p", &p); //指针变量的地址

    NSLog(@"%p", p); //对象的地址  

    NSLog(@"%@", p); // <类名:对象地址>

 

2.     +description

使用NSLog和%@输出某个类对象时,会调用类对象+description方法,并拿到返回值进行输出

 

    Class c =[Person class];

    NSLog(@"%@", c);

 

3.     修改NSLog的默认输出

重写-description或+description方法

 

4.     死循环

如果在-description方法中使用NSLog打印self,就会引起死循环。

 

    - (NSString*)description

    {

        // 下面代码会引发死循环

        // NSLog(@"%@",self);

        return [NSString stringWithFormat:@"age=%d,name=%@",_age, _name];

        //return@"3424324";

}

 

九、 SEL

1.     方法的存储位置

1)     每个类的方法列表都存储在类对象中

2)     每个方法都有一个与之对应的SEL类型的对象(数据)

3)     根据一个SEL对象就可以找到方法的地址,进而调用方法

4)     其实消息就是SEL

5)     SEL其实是对方法的一种包装,将方法包装成一个SEL类型的数据,去找对应的方法地址。找到方法地址就可以调用方法

 

2.     SEL对象的创建

    SEL s = NSSelectorFromString(@"test");

SEL s = @selector(test2:);

 

3.     SEL对象的用法

1)     把test方法包装成SEL类型的数据

2)     根据SEL数据找到对应的方法地址

3)     根据方法地址调用对应的方法

 

[p performSelector:@selector(test)];

    [p performSelector:s withObject:@"456"];

 

    @implementation Person

    - (void)test

    {

        // _cmd代表着当前方法的SEL

        NSString *str =NSStringFromSelector(_cmd);//SEL对象转为NSString对象

       

        // 会引发死循环

        // [selfperformSelector:_cmd];

 

        NSLog(@"调用了test方法-----%@", str);

    }

 

    - (void)test2:(NSString *)abc

    {

        NSLog(@"test2-----%@", abc);

    }

    @end

 

 

    int main()

    {

        Person *p = [[Personalloc] init];

        // 直接调用test方法

        [p test];

        [p test2:@"123"];

       

        // SEL对象的创建

        SEL s = NSSelectorFromString(@"test");

        SEL s = @selector(test2:);

   

        // 间接调用test方法

        [p performSelector:s]; // 可直接写:[pperformSelector:@selector(test)];

        [p performSelector:swithObject:@"456"];

       

        return 0;

}

 


0 0