OC核心语法

来源:互联网 发布:淘宝客机器人 编辑:程序博客网 时间:2024/05/01 14:25


一、点语法

点语法的本质是方法调用,就是调用的setter和getter方法。

#import <Foundation/Foundation.h>#import "Person.h"int main(){    Person *p=[Person new];    p.age=23; // 这就是点语法,xcode会自动将这个代码转为[p setAge:23]    NSLog(@"%d",p.age); // xcode会自动将点语法转为[p age]    return 0;}//编译器根据取值还是赋值来判断转为setter还是getter。@interface Person : NSObject{    int _age;}- (void)setAge:(int)age;- (int)age;@end@implementation Person- (void)setAge:(int)age{    _age=age;   // self.age=age; 这会死循环    NSLog(@"use-setter");//为了验证点语法是否调用setter方法}- (int)age{    NSLog(@"use-getter");//为了验证点语法是否覅用getter方法    //NSLog(@"%d",self.age);这会死循环,get方法不停地调用自己    return _age;}@end


二、成员变量的作用域
@private:只能在当前类的对象方法中直接访问。类的实现中的变量默认是private
@protected:可以在当前类以及子类的对象方法中直接访问。类的声明中的变量默认是protect。
@public:任何地方都可以直接访问
@package:同一个“体系内”(框架)可以访问,介于@private和@public之间


OC只支持单继承。

#import <Foundation/Foundation.h>
//Person类@interface Person : NSObject{    @protected    int _age;        @private    NSString *_name;}- (void)setAge:(int)age;- (int)age;- (void)setName:(NSString *)name;- (NSString *)name;@end@implementation Person{    int hight; // 在类的实现中定义了一个变量,这个变量是private,其他类均不能访问。}//_age的set和get- (void)setAge:(int)age{    NSLog(@"%d",self->hight); //本类可以直接访问hight    _age=age;   // self.age=age; 这会死循环    NSLog(@"use-setter");//为了验证点语法是否调用setter方法}- (int)age{    NSLog(@"use-getter");//为了验证点语法是否覅用getter方法    //NSLog(@"%d",self.age);这会死循环,get方法不停地调用自己    return _age;}//_name的set和get- (void)setName:(NSString *)name{    _name=name;}- (NSString *)name{    return _name;}@end
//Student类@interface Student : Person- (void)said;@end@implementation Student- (void)said{    /*    NSLog(@"my name is %@",self->_name);      这样是错误的,因为_name是Person中被private修饰的,子类不能直接访问.     但是Student类中有_name这个变量     */    NSLog(@"my name is %@,age is %d",self.name,self->_age); // _age可以被子类直接访问    // NSLog(@"%d",self->hight); 这是错误的,因为Person.h中根本没有hight这个变量}@endint main(){        Person *p=[Person new];    p.age=23; // 这就是点语法,xcode会自动将这个代码转为[p setAge:23]    NSLog(@"%d",p.age); // xcode会自动将点语法转为[p age]        //private修饰的变量虽然子类不能直接访问,但是在子类内部这些变量都有    Student *student=[Student new];    student.age=12;    student.name=@"xiaoming";    [student said];    return 0;}

三、@property和@synthesize

@property:自动生成某个成员变量的setter和getter方法的声明

如:@property int age;

编译器会自动将这句自动生成 -(void)setAge:(int)age;

                        和 -(int)age;

 

#import <Foundation/Foundation.h>#import "Person.h"int main(){        Person *p=[Person new];    p.age=23; // 这就是点语法,xcode会自动将这个代码转为[p setAge:23]    NSLog(@"%d",p.age); // xcode会自动将点语法转为[p age]    [p setName:@"liming"];    NSLog(@"%@",[p name]);    return 0;}@interface Person : NSObject{    int _age;    NSString *_name;}@property int age;/* int 就是set方法的参数类型和get方法的返回值类型, age 直接影响到set和get方法的名称  假如 @property int _age; 那么生成的set和get方法将分别是 -(void)set_age:(int)_age; - (int)_age; */@property NSString * name;@end@implementation Person//_age的set和get- (void)setAge:(int)age{    _age=age;;}- (int)age{    return _age;}//_name的set和get- (void)setName:(NSString *)name{    _name=name;}- (NSString *)name{    return _name;}@end

@synthesize:自动生成某个成员变量的set和get方法实现

如:@synthesize age=_age;(age:@property里写的是啥,这里就写啥。_age:这个变量写成什么,set和                           get里面就会访问什么变量)

这句话意味着会访问_age这个变量。       


因此上述代码中的Person类的实现可以写成:

@implementation Person//_age的set和get@synthesize age=_age;//_name的set和get@synthesize name=_name;// @synthesize age=_age,name=_name;这可以连着写//@property 也可以连着写 @proerty int age,hight; (age和hight必须都是int类型)@end

@synthesize age=_age;这句代码访问_age这个变量,如果不存在,那就会自动生成一个@private类型的_age变量。

所以上述代码可以简化为:

#import <Foundation/Foundation.h>@interface Person : NSObject //类的声明//自动生成相应的set和get方法声明@property int age;@property NSString * name;@end@implementation Person // 类的实现//自动生成变量_age和_name.且自动生成相应的get和set方法的实现@synthesize age=_age,name=_name;@end

随着xcode不断升级,@synthesize语句也可以简化不写

因此代码能进一步简化到:

#import <Foundation/Foundation.h>//类的声明@interface Person : NSObject//自动生成相应的set和get方法声明,同时也实现了这些方法,而且还自动生成了私有的_age和_name@property int age;@property NSString * name;@end//类的实现@implementation Person@end


注意:1.@synthesize age;这里没有注明访问哪个变量,那么就会默认访问跟age一样的变量,也就是会访问成员变         量age而不是_age。假如age这个变量不存在,就会自动生成age。

      2.代码中没有相应的set和get方法时,Xcode才会自动生成。有,就不生成,同时变量也不会生成(因为生成         变量的目的就是为了在set和get中使用)。

若手动实现了setter方法,编译器就只会自动生成getter方法
若手动实现了getter方法,编译器就只会自动生成setter方法
若同时手动实现了setter和getter方法,编译器就不会自动生成不存在的成员变量

四、id类型

      万能指针,能指向任何OC对象,相当于NSObject *
注意:id后面不要加上*
id p = [Person new];


五、构造方法

构造方法是用来初始化对象的方法。

重写构造方法

完整地创建一个可用的对象,分为两步:

 1>分配存储空间 (类方法:+(id)alloc,返回一个分配好内存空间的对象,但是没有初始化) 

 2>初始化 (对象方法:-(id)init,返回初始化好的对象)

new就是包含了alloc和init两个方法。

init就是构造方法。

重写init方法分三步:

  1>调用父类init方法,且赋值给self,初始化父类中声明的一些成员变量和其他属性。

  2>判断self是否为空。不为空才算初始化成功,才有必要进行自定义的初始化内容。

  3>返回self。

#import <Foundation/Foundation.h>@interface Person : NSObject//自动生成相应的set和get方法声明,同时也实现了这些方法@property int age;@property NSString * name;@end@implementation Person//重写init方法- (id)init{    if(self=[super init])    {        _age=23;        NSLog(@"Person 初始化完毕,age=%d",_age);    }    return self;}@endint main(){     Person *p=[[Person alloc]init];    p=[Person new]; // 可见直接调用new是一样的,因为new本来就是包含了alloc和init     return 0;}
//程序结果://2014-12-12 19:18:31.558 核心语法[1137:303] Person 初始化完毕,age=23//2014-12-12 19:18:31.561 核心语法[1137:303] Person 初始化完毕,age=23


自定义构造方法

规范:1>一定是对象方法,一定是以-开头

      2>返回值一般是id类型

      3>方法名一般以initWith开头

#import <Foundation/Foundation.h>//Persdon类@interface Person : NSObject//自动生成_age和_name,且自动生成他们的set和get方法声明及实现@property int age;@property NSString *name;//自定义构造方法- (id)initWithAge:(int)age andName:(NSString *)name;@end@implementation Person//自定义构造方法的实现- (id)initWithAge:(int)age andName:(NSString *)name{    if(self=[super init])    {        _age=age;        _name=name;    }    return self;}@end//Student类@interface Student : Person@property int number;//自定义构造方法- (id)initWithAge:(int)age andName:(NSString *)name andNumber:(int)number;@end@implementation Student//实现自定义构造方法- (id)initWithAge:(int)age andName:(NSString *)name andNumber:(int)number{    //父类内部的成员变量,尽量用父类自己的方法访问    if(self=[super initWithAge:age andName:name])    {        _number=number;    }    return self;}@endint main(){    //用自定义的构造方法初始化对象    Person *p=[[Person alloc] initWithAge:23 andName:@"LIMING"];    NSLog(@"age--%d,name--%@",p.age,p.name);        Student *s=[[Student alloc]initWithAge:34 andName:@"haha" andNumber:1234];    NSLog(@"age=%d,name=%@,number=%d",s.age,s.name,s.number);    return 0;}

六、分类(category)

可以给某个类扩充一些方法,在不修改原来类的代码的情况下。

格式:

//分类声明@interface 类名(分类名称)@end//分类实现@implementation 类名(分类名称)@end

注意:

1.分类只能加方法,不能加成员变量。

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

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

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

  (Xcode中调整.m文件编译顺序:点击项目名称->Build Phases->Compile Sources,在这里上下拖动可以调换顺序)

#import <Foundation/Foundation.h>//NSString类的分类@interface NSString (numCount)//声明方法计算字符串中数字的个数,一个类方法,一个对象方法+ (int)countOfString:(NSString *)str;- (int)count;@end@implementation NSString (numCount)+ (int)countOfString:(NSString *)str{    int count=0;    for(int i=0;i<[str length];i++)    {        //判断每个位置上德字符是不是在0-9之间        if([str characterAtIndex:i]>='0'&&[str characterAtIndex:i]<='9')            count++;    }    return count;}- (int)count{    //直接调用类方法    return [NSString countOfString:self];}@end//Persdon类@interface Person : NSObject//自动生成_age和_name,且自动生成他们的set和get方法声明及实现@property int age;@property NSString *name;@end//preson类的实现@implementation Person@end//Person的分类@interface Person (Beijing)- (void)test;@end@implementation Person (Beijing)- (void)test{    NSLog(@"%@",@"beijing");}@end//Person的分类@interface Person (Nanjing)- (void)test;@end@implementation Person (Nanjing)- (void)test{    NSLog(@"%@",@"nanjing");}@endint main(){        Person *p=[[Person alloc] init];    [p test];//调整Person两个分类的编译顺序时,结果是不同的        NSLog(@"%d",[NSString countOfString:@"123"]);//调用自定义的类方法    NSLog(@"%d",[@"s1d" count]); // 调用自定义的对象方法        return 0;}
八、 类的本质
1. 类也是个对象
 其实类也是一个对象,是Class类型的对象,简称“类对象”。
   类名就代表着类对象,每个类只有一个类对象。
   Class类型的定义:typedef struct objc_class *Class;(也就是本质是指针)

2. +load和+initialize
 +load
 在程序启动的时候会加载所有的类和分类,并调用所有类和分类的+load方法
 先加载父类,再加载子类;也就是先调用父类的+load,再调用子类的+load
 先加载元原始类,再加载分类
 不管程序运行过程有没有用到这个类,都会调用+load加载

 +initialize
 在第一次使用某个类时(比如创建对象等),就会调用一次+initialize方法
 一个类只会调用一次+initialize方法,先调用父类的,再调用子类的(要是分类重写了initialize方法,就直接调用分类的,原始类就不调用了)

3. 获取类对象的2种方式
Class c = [Person class]; // 类方法
或者
Person *p = [Person new];
Class c2 = [p class]; // 对象方法

4. 类对象调用类方法
Class c = [Person class];
Person *p2 = [c new];
#import <Foundation/Foundation.h>//Persdon类@interface Person : NSObject+ (void)test;@end//preson类的实现@implementation Person+ (void)test{    NSLog(@"Person的类方法-test");}+(void)load{    NSLog(@"Person----------load");}+ (void)initialize{    NSLog(@"Person-----initialize");}@end//Person的分类@interface Person (Beijing)@end@implementation Person (Beijing)+(void)load{    NSLog(@"Person (Beijing)----------load");}+ (void)initialize{    NSLog(@"Person (Beijing)-----initialize");}@end//Student类@interface Student : Person@end@implementation Student+(void)load{    NSLog(@"Student----------load");}+ (void)initialize{    NSLog(@"Student-----initialize");}@endint main(){    Person *p=[[Person alloc] init];    Class c=[Person class]; // 通过类方法获取Person的类对象    Class c1=[p class]; // 通过对象方法获取Person的类对象    NSLog(@"%p---%p",c,c1); //地址相同,即二者都是指向Person类对象,这个类对象只有一个        //类对象调用类方法    [c test];    Person *p1=[c new];        return 0;}//执行结果://2014-12-13 00:04:37.832 核心语法[2141:303] Person----------load//2014-12-13 00:04:37.834 核心语法[2141:303] Student----------load//2014-12-13 00:04:37.835 核心语法[2141:303] Person (Beijing)----------load//2014-12-13 00:04:37.836 核心语法[2141:303] Person (Beijing)-----initialize//2014-12-13 00:04:37.837 核心语法[2141:303] 0x1000012c0---0x1000012c0//2014-12-13 00:04:37.837 核心语法[2141:303] Person的类方法-test

九、descrition方法
1. -description方法
  使用NSLog和%@输出某个对象时(默认输出的是“类名+内存地址”),会调用对象的-description方法,并拿到返回值进行输出
2. + description方法
  使用NSLog和%@输出某个类对象时(默认输出类名),会调用类对象+description方法,并拿到返回值进行输出

3. 死循环陷阱
 如果在-description方法中使用NSLog打印self


注意:NSLog输出C语言字符串时,字符串内不能含有中文

#import <Foundation/Foundation.h>//Persdon类@interface Person : NSObject@property int age;@property NSString *name;@end//preson类的实现@implementation Person//重写类方法+ (NSString *)description{    return @"=======";}//重写对象方法- (NSString *)description{    return [NSString stringWithFormat:@"Persion-age=%d,name=%@",self.age,self.name];}@endint main(){    Person *p=[[Person alloc] init];    p.age=12;    p.name=@"xiaoming";    NSLog(@"%@",p); // 会调用对象的description方法        Class c=[Person class];    NSLog(@"%@",c); //会调用类的description方法    return 0;}//运行结果://2014-12-13 01:05:00.812 核心语法[2397:303] Persion-age=12,name=xiaoming//2014-12-13 01:05:00.815 核心语法[2397:303] =======

十、SEL

1. 方法的存储位置

   每个类的方法列表都存储在类对象中
   每个方法都有一个与之对应的SEL类型的对象
   根据一个SEL对象就可以找到方法的地址,进而调用方法

   SEL类型的定义:typedef struct objc_selector *SEL;

#import <Foundation/Foundation.h>//Persdon类@interface Person : NSObject- (void)test;- (void)test1:(NSString *)name;- (void)name:(int)num;@end//preson类的实现@implementation Person- (void)test{    NSLog(@"---------");}- (void)test1:(NSString *)name{    NSLog(@"name=%@",name);}/* 每个方法都有一个隐藏的SEL数据类型:_cmd,这个数据代表方法本身 同样的,知道一个方法的SEL类型,也可以变成字符串 */- (void)name:(int)num{    NSString *name1=NSStringFromSelector(_cmd);    NSLog(@"%@--%d",name1,num);}@endint main(){    Person *p=[[Person alloc] init];        [p test];//直接调用对象方法test    [p performSelector:@selector(test)]; // 间接调用    /*     直接调用对象方法的过程:     1.把该方法包装成SEL类型的数据     2.根据SEL数据找到对应的方法地址     3.根据方法地址调用对应的方法     */        //创建SEL对象    SEL s=@selector(test1:);        //间接调用带参数的方法    [p performSelector:s withObject:@"lixiao"];        //假如知道一个方法名得字符串形式,也可以转换为SEL    NSString *name=@"test1:";    SEL s1=NSSelectorFromString(name);// 调用了一个函数,将字符串转换为SEL    [p performSelector:s1 withObject:@"hah"];        [p name:23];//打印函数名称        return 0;}
SEL其实是对方法的一种包装,将方法包装成SEL类型的数据,去找对应方法的地址,找到方法地址就可以调用该方法。消息机制的消息就是SEL



0 0
原创粉丝点击