OC-4-语法总结

来源:互联网 发布:青花瓷 知乎 编辑:程序博客网 时间:2024/05/15 11:53
传统的get和set方法

点语法的介绍和使用
对象.属性名
p.name= @"凤姐";
p.age= 12;
注意:此时(对象.属性名)并不是直接访问实例变量,而是Xcode看到点语法后,会自动帮我们替换为
[p setName:@凤姐"];
[p setAge:12];
同理,对象.属性名在等号右侧,也会自动替换get方法

点语法:Xcode特性,Xcode帮我们做代码替换。在等号左侧为set方法,在等号右侧为get方法(设置值,还是取值)。

注意事项:
点语法的本质是方法调用,而不是访问成员变量。当使用点语法时,编译器会自动展开成相应地方法。切记点语法的本质是替换为相应地set和get方法,如果没有set和get方法,则不能够使用点语法。

@property关键字:省略方法的声明
@property是编译器指令,告诉编译器要做什么
@property 告诉编译器声明属性的访问器(getter和setter)方法
好处:免去手工书写get和set方法繁琐的代码

@property的用法:@property  类型名  名称;(最好是:去掉下划线的实例变量
注意事项:1、实现get和set方法的声明
2、@property只能写在@interface 和@end之间
3、如果@property后面的类型一致,可以写在一起

@synthesize关键字:省略方法的实现
@synthesize也是编译器指令
@synthesize在.m文件中定义set和get方法的实现
@synthesize的用法:@synthesize  名称;(与上面的一样
注意事项:1、@synthesize在@interface和@end之间
2、@synthesize后的名称必须在.h中声明
3、如果@synthesize后面的类型一致,可以写在一起。不一致也可以写在一起,但是不同类型需要区分。

@synthesize指定实例变量赋值
1、@synthesizename;//操作的是name,name有值
2、@synthesizeweight = _weight;//操作的是实例变量_weight,_weight有值
3、不指定赋值,会生成name。指定实例变量赋值后,会生成_weight,set赋值和get返回值同以前调用方法时的操作

@property增强使用
1、xcode4.4之后,可以只使用@property,而不使用@synthesize。
2、声明和实现了get和set方法,操作的是带有下划线的实例变量。
3、如果当前类没有下划线的实例变量,系统会帮助我们生成
//只需要@property语句
@propertyint age;           //系统自动生成 int _age;
@propertyNSString *name;   //系统自动生成 NSString*_name;

系统自动生成的变量,子类不能继承,完全私有化,且不可见。但是使用@property展开的方法,子类可以重写。
@property增强之后的get和set方法的重写:防止非法赋值,get和set方法只能重写一个

动态类型:程序直到执行时才能确定所述的类
静态类型:将一个变量定义为特定类的对象时,使用的是静态形态,编译时就知道所属的类

id类型及应用场景
1、NSObject访问子类
        Animal*ani = [Animalnew];
        [anirun];//动物会跑
       
       
Animal *ani2 = [Dog new];
        [ani2
run];//多态
       
       
NSObject *obj = [Animal new];
        [(
Animal *)obj run];//NSObject访问子类
       
        obj = [
Dog new];
        [(
Dog *)obj run]; //访问子子类
       
       //NSObject是所有类的基类,可以指向任何子类,指向时要强制转换

2、id类型
id类型是一种通用型指针,可以转换为任何类型,又称为万能指针
注意:在id的定义中,已经包装好了*号,id指针只能指向OS的对象
//id的使用
       
id obj2;    //只能指向对象
        obj2 = ani; 
//传一个对象
        [obj2
run];
       
//NSObjectid都可以指向任何对象
       
//NSObject对象会进行编译时检查(需要强制类型转换)
       
//id不需要强制转换,id可以直接使用
       //编译器看到id以后,认为是动态类型,不检查类型
instancetype和id的异同:
1、相同点:都可以作为方法的返回类型
2、不同:1)instancetype可以返回和方法所在类相同类型的对象,id只能返回未知类型的对象(只有运行时才知道)
               2)instancetype只能作为返回值,不能像id那样为作为参数

3、动态类型
动态绑定:在objuect-c中,一个对象是否调用指定的方法不是有编译器决定而是由运行时决定,这种称为方法的动态绑定
动态类型检测方法
对象在运行时获取其类型的能力称为内省。内省有多种方法实现。
1)判断类型
-(BOOL) isKandOfClass : classObj 判断实例对象是否是这个类或者这个类的子类的实例
Animal*ani = [Animalnew];
       
//ani 是否是Animal得实例对象
       //动态类型检测:
       //1、判断类型
       //1) 使用格式:[对象isKindOfClass 类对象]
       
      
BOOL isInstance = [ani isKindOfClass:[Animalclass]];
       NSLog(@"%d", isInstance);
-(BOOL) isMemberOfClass : classObj 判断是否是这个类的实例不管是否是这个类的子类的实例
//2)使用格式:[对象isKindOfClass :类对象]
       
Dog *dog = [Dog new];
        isInstance = [dog
isMemberOfClass:[Animalclass]];
       NSLog(@"%d", isInstance);
+(BOOL) isSubclassOfClass : classObj 判断类是否是指定类的子类
//3)使用格式:[类AisSubclassOfClass : 类B](类与类之间的关系)
          //类A是否是类B的子类
      BOOL isSub = [Dog isSubclassOfClass:[Animalclass]];
       
//通过对象来获取类对象
        isSub = [[dog
class]isSubclassOfClass:[aniclass]];
       NSLog(@"%d", isSub);

2)指定方法响应的检测
- (BOOL)respondsToSelector:(SEL)aSelector; 判断对象能否响应指定的方法
//使用格式:[对象respondsToSelector (SEL)]
       SEL s1 = @selector(eat);//eat包装为SEL类型
       
BOOL isRespond = [ani respondsToSelector:s1];
       
NSLog(@"%d", isRespond);
       
if (isRespond) {
            [(
Dog *)ani eat];
        }
else {
           
NSLog(@"不能调用此方法");
        }
+ (BOOL)instancesRespondToSelector:(SEL)aSelector; 判断类能否响应指定的方法
//使用格式:[instancesRespondToSelector : (SEL)]
        isRespond = [
DoginstancesRespondToSelector:s1];
       NSLog(@"%d", isRespond);

3)应用selector指定的方法
响应无参方法
- (id)performSelector:(SEL)aSelector;
响应有参方法
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
Animal*ani = [Animalnew];
       
if ([ani respondsToSelector:@selector(eat)]) {
           
//[(Dog *)ani eat];
           
//不写上面的形式,响应无参方法
            [ani
performSelector:@selector(eat)];
           //响应有参方法
            [aniperformSelector:@selector(eat:) withObject:@"骨头"];
        }else {
           
NSLog(@"不能调用此方法");
        }

构造方法
构造方法:用来初始化对象的方法,是对象方法,-开头
重写构造方法的目的:为了让对象创建出来,成员变量就会有一些固定的值
1)构造方法的调用
new可以拆为alloc分配空间和init初始化对象,然后返回对象首地址
OC中的构造方法:给对象进行初始化的方法(init方法:对象方法,该方法返回的是一个对象(调用init的对象)
2)重写构造方法
//子类把父类的init覆盖,默认先执行子类
- (
instancetype)init {
   
//先让父类把父类原来做的事情做完
   
self = [super init];
   
//判断父类是否初始化成功,成功不为空
   
if (self) {
       
//此处写子类的代码内容
       
_age = 10;
    }
   
   
return self;//self指代的是方法的调用者
}
问题:
1、[super init]的作用
     面向对象的体现,先利用父类的init方法为子类实例的父类部分属性初始化
2、self为什么要赋值为[super init]
     简单的说是为了防止父类的初始化方法release掉了self指向的空间,并重新alloc了一块空间。这时的话,[super init]可能alloc失败,这时就不再执行if中的语句。
3、super作为消息接收者的实质
     super并不是真正的指针,[super message]的实质是由self来接受父类的message,需要注意的是,[super message]中,message方法出现的self为[super message]语境中的self,即子类实例

自定义构造方法
1)自定义构造方法的规范
1、一定是对象方法,以-开头
2、返回值一般是id类型
3、方法名一般以initWith开头

2)自定义构造方法使用
#import"Person.h"

@implementation Person
//-(instancetype)init{
//    if (self = [super init]) {
//        _name = @"凤姐";
//        _age = 18;
//    }
//    return self;
//}//这样就写死了
-(
instancetype)initWithName:(NSString*)name andAge:(int)age{
   
   
if (self = [super init]) {
       
_name = name;
       
_age = age;
    }
   
return self;
}
@end


 //用指定的值进行初始化
       
//创建对象时,用我们制定的名字和年龄进行初始化
       
Person *p1 = [[Person alloc] initWithName:@"陈子超"andAge:18];
       NSLog(@"%@,%d", p1.name, p1.age);

//创建一个学生类,继承人类,要求初始化就设置了姓名,年龄,学号
#import"Student.h"

@implementation Student
-(
instancetype)initWithName:(NSString*)name andAge:(int)age andIdNum:(int)idNum{
   
if (self = [super initWithName:name andAge:age]) {//初始化父类的initWith
       
_idNum = idNum;
    }
   
return self;
   
}
@end


 Student*stu = [[Studentalloc]initWithName:@"陈子超"andAge:24andIdNum:18];
       NSLog(@"%@,%d,%d", stu.name, stu.age, stu.idNum);
0 0