您的位置:首页 > 职场人生

黑马程序员_第八天视频学习 类和对象的核心语法

2014-05-02 22:21 323 查看
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
一、  点语法

属于编译器特性
1、点语法与setter和getter有关
 

#import <Foundation/Foundation.h>

 

@interface Person :
NSObject

{

    int _age;

    NSString *_name;

}

 

- (void)setAge:(int)age;

- (int)age;

 

- (void)setName:(NSString *)name;

- (NSString *)name;

 

@end

@implementation Person

 

- (void)setAge:(int)age

{

    _age = age;

    NSLog(@"setAge");

   

    // 会引发死循环

    // self.age = age; // 相当于[selfsetAge:age];

}

- (int)age

{

    NSLog(@"age");

   

    // 访问的两种方法

    return
_age;

    // return self->_age;

   

    // 会引发死循环

    // return self.age; // 相当于[selfage];

}

 

- (void)setName:(NSString *)name

{

    _name = name;

}

-(NSString *)name

{

    return
@"Rose";

}

 

@end

int main(int argc,
const char * argv[])

{

    Person *p = [Person
new];

    [p setAge:10];

    int a = [p
age];

    NSLog(@"%d",a);

   

    p.age =
15;

    int b = p.age;

    NSLog(@"%d",b);

   

    p.name =
@"jack";

    NSString *s = p.name;

    NSLog(@"%@",s);

   

    return
0;

}

 

p.age = 10;当编译器遇到点语法的时候,自动将代码转成[p setAge:10];

点语法的本质还是方法的调用;

点语法判定是set还是get方法,就是看是否赋值;

          验证点语法的本质是setter\getter方法:在setter\getter里做打印或使用断点调试。
2、点语法的注意点
     setter和getter里不能写self.age = age;或return self.age;会引发死循环。

 
二、  成员变量的作用域

有4种类型:

         1)、@public:任何地方都能直接访问对象的成员变量
         2)、@private:只能在当前类的对象方法中直接访问 (@implementation中默认就是@protected)
         3)、@protected:可以在当前类和子类的对象方法中直接访问 (@interface中默认就是@protected)
         4)、@package:只要处于同一个框架中,就能直接访问对象的成员变量,介于@private和@public之间的。

                    
三、  @property和@synthesize

帮助类自动生成setter和getter,也属于编译器特性
1、 @property和@synthesize定义

@property 数据类型 成员变量名(去下划线 _ ):可以自动生成某个成员变量的setter和getter声明;@property用在@interface @end之间

@synthesize成员变量名(去下划线 _ ) = 成员变量名:可以自动生成某个成员变量的setter和getter实现,并且访问_age这个成员变量;@synthesize用在@implementation @end之间

2、定义成员变量的最简写法
     @interface Car : NSObject
     // 生成@private的数据类型为double的成员变量_height,并生成_height的setter和getter的声明和实现
     @property double height;
     @end
3、
     若手动实现了setter,编译器只会自动生成getter和自动生成不存在的成员变量;
     若手动实现了getter,编译器只会自动生成setter和自动生成不存在的成员变量;
     若手动实现了setter和getter,编译器就不会自动生成不存在的成员变量;

 
四、  id

id(内部已包含*)是万能指针,能指向/操作任何OC对象(只适用于OC对象);

id 可以认为 id == NSObject *;

 
五、  构造方法

完整地创建一个可用的对象:
       1)、分配存储空间(+alloc)
       2)、初始化(+init)
创造对象不要用new,应使用
       Person *p =[[Person alloc] init];
1、 构造方法:用来初始化对象的方法,是个对象方法,减号 – 开头;
2、 重写构造方法的目的:为了让对象创建出来,成员变量就会有一些固定的值。
重写 – init 方法

-(id)init

{

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

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

   

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

    if (self != nil) {

        // 初始化成功

        _age = 10;

    }

   

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

    return self;

}

最终写法

- (id)init

{

    if( self = [super init])

    {

        _age = 10;

    }

    return self;

}

3、 重写构造方法的注意点
a)     先调用父类的构造方法([super init])
b)     再进行子类内部成员变量的初始化
4、 自定义构造方法
              自定义构造方法的规范
                    1)、一定是对象方法,一定以 - 开头
                    2)、返回值一般是id类型
                     3)、方法名一般以init开头

 #import <Foundation/Foundation.h>

 

@interface Person : NSObject

@property NSString *name;

@property int age;

 

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

- (id)initWithAge:(int)age;

- (id) initWithName:(NSString *)name andAge:(int)age;

@end

@implementation Person

 

- (id)initWithName:(NSString *)name

{

    if ( self = [superinit] ) {

        _name =name;

    }

    return self;

}

 

- (id)initWithAge:(int)age

{

    if (self =[super init]) {

        _age = age;

    }

    return self;

}

 

- (id)initWithName:(NSString *)name andAge:(int)age

{

    if (self =[super init]) {

        _age = age;

        _name =name;

    }

    return self;

}

 

 

- (id)init

{

    if (self =[super init]) {

        _name =@"jack";

    }

    return self;

}

@end

@interface Student : Person

@property int no;

 

- (id)initWithNo:(int)no;

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

@end

@implementation Student

 

- (id)initWithNo:(int)no

{

    if (self =[super init]) {

        _no = no;

    }

    return self;

}

/*

- (id)initWithName:(NSString *)name andAge:(int)ageandNo:(int)no

{

    if ( self = [super init] )

    {

        _no = no;

        self.name =name;

        self.age =age;

        // 第二种写法

        // [selfsetName:name];

        // [selfsetAge:age];

       

    }

    return self;

}

*/

 

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

- (id)initWithName:(NSString *)name andAge:(int)ageandNo:(int)no

{

    // 将父类定义的属性name、age传递到父类方法中进行初始化

    if (self =[super initWithName:name andAge:age]) {

        _no = no;

    }

    return self;

}

@end

int main(int argc, const char * argv[])

{

 

    @autoreleasepool{

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

       NSLog(@"%@",p.name);

       

        Person *p1= [[Person alloc] initWithName:@"Rose"];

       NSLog(@"%@",p1.name);

       

        Person *p2= [[Person alloc] initWithAge:20];

        NSLog(@"%d",p2.age);

       

        Person *p3= [[Person alloc] initWithName:@"jim" andAge:19];

        NSLog(@"name = %@, age = %d",p3.name,p3.age);

       

        Student*stu = [[Student alloc] initWithNo:2];

       NSLog(@"no = %d",stu.no);

        

        Student*stus = [[Student alloc] initWithName:@"张三" andAge:16 andNo:5];

       NSLog(@"name = %@, age = %d, no =%d",stus.name,stus.age,stus.no);

       

    }

    return 0;

}

 

六、  Category分类

可以给某一个类扩充一些方法(不修改原来的类的代码);
分类的作用:在不改变原来类模型(内容)的基础上,可以为类增加一些方法。
使用注意:
       1)、分类只能增加方法,不能增加成员变量
      2)、分类方法实现中可以访问原来类中的成员变量
      3)、分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会导致原来的方法没法再使用
      4)、方法调用的优先级:分类(最后参与编译的分类优先) --> 原来类 --> 父类
/*
 ➢  给NSString增加一个类方法:计算某个字符串中阿拉伯数字的个数
 ➢  给NSString增加一个对象方法:计算当前字符串中阿拉伯数字的个数
 */

#import<Foundation/Foundation.h>

 

@interfaceNSString (Number)

 

-(int)numberCount;

+(int)numberCountOfString:(NSString *)str;

 

@end

@implementationNSString (Number)

 

//+(int)numberCountOfString:(NSString *)str

//{

//    // 1、定义变量计算数字的个数

//    int count = 0;

//    for (int i = 0; i < str.length; i++) {

//        // 2、取出i这个位置对应的字符

//        unichar c = [str characterAtIndex:i];

//

//        // 3、如果这个字符是阿拉伯数字,count自增1

//        if ( c >= '0' && c <= '9') {

//            count++;

//        }

//    }

//    return count;

//}

 

+(int)numberCountOfString:(NSString *)str

{

    return [str numberCount];

}

 

-(int)numberCount

{

    int count = 0;

    for (int i = 0; i < self.length; i++) {

        unichar c = [self characterAtIndex:i];

        if ( c >= '0' && c <= '9') {

            count++;

        }

    }

    return count;

}

 

@end

intmain(int argc, const char * argv[])

{

 

    @autoreleasepool {

        int count = [NSStringnumberCountOfString:@"sfa7sf6a78gsdfa7"];

        NSLog(@"%d",count);

       

        int counts = [@"hjsdhj4389jsdjk94"numberCount];

        NSLog(@"%d",counts);

       

    }

    return 0;

}

 
七、  类的深入研究

1、类的本质
       类也是一个对象,是Class类型的对象,简称类对象
              // 利用Person这个类创建了Person类型的对象
        Person *p = [[Person alloc] init];
       
        Person *p1 = [[Person alloc] init];
       
        // 获取内存中的类对象
        Class c = [p class];
        Class c1 = [p1 class];
        Class c2 = [Person class];
       
        NSLog(@"c = %p, c2 = %p, c2 =%p",c,c1,c2); // 输出结果都是一样的
       本质是:
       1)、利用Class 创建 Person类对象
       2)、利用Person类对象  创建Person类型的对象
       类名就代表类对象:类对象 == 类
2、+load方法和+initialize方法
       1)、 当程序启动时,就会加载项目中所有的类和分类,而且加载完毕后就会调用每个类和分类的+load方法。只会调用一次;
       2)、 当第一次使用某个类的时候,就会调用当前类和父类的+initialize方法,如果类有分类,按优先级加载+initialize方法;

       3)、 先加载父类、再加载子类 (先调用父类的+load方法,再调用子类的+load方法),先初始化父类、再初始化子类 (先调用父类的+initialize方法,再调用子类的+initialize方法);
       可以用+initialize监听类的初始化过程
 

八、  description

1、 -description方法
       使用NSLog和%@输出某个对象时,会调用对象的-description方法,并拿到返回值进行输出
2、 + description方法
       使用NSLog和%@输出某个类对象时,会调用类对象+description方法,并拿到返回值进行输出
3、 修改NSLog的默认输出
       重写-description或者+description方法即可

@implementation Person

 

// 决定了实例对象的输出结果

- (NSString *)description

{

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

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

   

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

}

 

// 决定了类对象的输出结果

+ (NSString *)description

{

    return
@"sdf";

}

@end

4、NSLog输出补充

//输出代码行号

NSLog(@"%d",__LINE__);

 // NSLog输出C语言字符串的时候,不能有中文

// 输出源文件的名称

NSLog(@"%s",__FILE__);

printf("%s\n",__FILE__);

 // 输出当前函数名

NSLog(@"%s",__func__);

 

九、  SEL

是一种类型,这种类型的数据就代表方法;
SEL其实是对方法的一种包装,将方法包装成一个SEL类型的数据,去找对应的方法地址,找到方法地址就可以调用方法;
每个类的方法列表都存储在类对象中;
每个方法都有一个与之对应的SEL类型的对象;
根据一个SEL对象就可以找到方法的地址,进而调用方法;

@interface Person :
NSObject

 

+ (void)test;

- (void)test2;

- (void)test3:(NSString *)abc;

@end

@implementation Person

 

+ (void)test

{

    NSLog(@"+test");

}

 

- (void)test2

{

    // _cmd代表着当前方法;每个方法内部都有一个内置的_cmd

    NSString *str =
NSStringFromSelector(_cmd);

   

    // 会引发死循环

    // [selfperformSelector:_cmd];

   

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

}

 

- (void)test3:(NSString *)abc

{

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

}

 

@end

int main(int argc,
const char * argv[])

{

 

    @autoreleasepool {

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

       

        // 间接调用test2方法

        [p performSelector:@selector(test2)];

       

        [p test3:@"ddff"];

       

        [p performSelector:@selector(test3:)
withObject:@"vxwe"];

       

        SEL s =@selector(test3:);

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

       

        [p test2];

        // 1、首先会把test2包装成SEL类型的数据

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

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

       

        NSString *name =
@"test2";

       

        SEL sl =
NSSelectorFromString(name);

       

        [p performSelector:sl];

       

        [p test2];

       

    }

    return
0;

}

         其实消息就是SEL   
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐