OC核心语法


一、点语法

点语法的本质是方法调用,就是调用的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这个变量
}
@end

int 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;
}
@end

int 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;
}
@end


int 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");
}
@end

int 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");
}
@end

int 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];

}
@end

int 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);
}
@end

int 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值