zoukankan      html  css  js  c++  java
  • Objective-C 【@property和@synthesize关键字】

    ———————————————————————————————————————————
    @property关键字的使用及注意事项

    直接上代码和注释了!

    //
    //@property关键字的使用
    //①使用格式:  @property  数据类型  方法名(去掉set后的)
    //  作用:在Xcode4.4之前,用于帮我们实现get/set方法的声明(只是实现了声明部分,实现部分自己写);在Xcode4.4之后,有增强功能。
    //②就一个注意事项,要说的是在使用@property关键字的时候,后面的方法名一定要正确,那么不正确会怎样呢?
    //举个例子:
    //下面 @property int age; 这句话,如果写成 @property int _age; 我们来测试一下。
    //在下面的测试中,我们发现,只在方法名前面加了一个下划线,但是我们为此所做的调整非常的多。我们很清楚,一改全改。在Person.m文件中我们发生了这样的改动:

    //-(void)set_age:(int)_age
    //{
    //    NSLog(@"这是age的set方法!");
    //    self->_age=_age;
    //}
    //-(int)_age
    //{
    //    NSLog(@"这是age的get方法!");
    //    return self->_age;
    //}

    //我们可以清楚的看到,我们set方法名发生的变化,然后传入的参数名也发生了变化(和实例变量名同名了),由于同名,我们还用了self关键字,在get方法中也是利用了self关键字进行返回值
    //所以说,我们最好不要改变@property后面的方法名,否则会带来不必要的麻烦


    //代码正文:

    #import <Foundation/Foundation.h>

    @interface Person : NSObject
    {
        NSString *_name;
        int _age;
    }

    @property NSString * name;
    //-(void)setName:(NSString *)name;
    //-(NSString *)name;

    //@property int age;//先注释掉,然后将age换成_age
    @property int _age;//首先,肯定会出错,然后我们应该怎么改呢?我们要知道,这时的方法名已经变成了 _age 了。
    //-(void)setAge:(int)age;
    //-(int)age;

    @end

    @implementation Person
    -(void)setName:(NSString *)name
    {
    //    NSLog(@"这是name的set方法!");
        _name=name;
    }
    -(NSString *)name
    {
    //    NSLog(@"这是name的get方法!");
        return _name;
    }

    -(void)set_age:(int)_age
    {
        NSLog(@"这是age的set方法!");
        self->_age=_age;
    }
    -(int)_age
    {
        NSLog(@"这是age的get方法!");
        return self->_age;
    }
    @end

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
    //        Person *p=[Person new];
    //        p.name=@"wang";
    //        p.age=20;
    //        NSLog(@"name = %@,age = %d",p.name,p.age);

            Person *p1=[Person new];
            
            p1._age=18;//[3819:437482] 这是age的set方法!
            NSLog(@"p1._age= %d",p1._age);//[3819:437482] 这是age的get方法![3819:437482] p1._age= 18
        }
        return 0;
    }


    ———————————————————————————————————————————
    @synthesize关键字的使用及注意事项

    /*

    代码格式:  @synthesize   方法名 (应该和@property  后面跟的一致)
     
     注意:
    要先在@interface ... @end中定义这个变量,然后用@property写他的set、get方法的声明,最后再在@implementation ... @end中写@synthesize 实现set、get方法。所以说,要想用@synthesize实现set、get方法,上面的两条(1.声明变量 2.使用@property关键字)缺一不可!!!(搭配使用)
     
     */


    上代码:

    #import <Foundation/Foundation.h>

    @interface Person : NSObject
    {
        NSString *_name;
        int _age;
    }
    //这里声明了两个成员变量的set和get方法
    @property NSString * name;
    @property int age;

    -(void)test;//用来检测当前的实例对象值,此时的结果是 [4031:471936] _name=(null),_age=0
    //为什么呢?那么我们来看一下刚刚我们的实现是怎么写的!
    //-(void)test
    //{
    //    NSLog(@"_name=%@,_age=%d",_name,_age);//这里显然用了_name来输出当前的实例对象的值,但是这里是不对的。我们刚才提到了,@synthesize在使用的时候事先为我们创建了一个新的变量name,所以说,当前的值应该输出当前的name,而不是_name。
    //}

    @end

    @implementation Person

    //@synthesize作用:帮我们实现了 实例变量的get和set方法
    //下面我们将下面的@synthesize关键字展开,看看里面到底是怎么实现的。

    @synthesize name;//我们只展开name这个成员变量的get和set方法实现,@synthesize name;句话展开之后为:
    //首先我们明白一点,@synthesize为我们新创建了一个变量name
    //-(void)setName:(NSString *)name
    //{
    //    self->name=name;//这里为什么不是 _name=name; 那就是因为@synthesize为我们新创建了一个变量name
    //}
    //-(NSString *)name
    //{
    //    return name;
    //}

    @synthesize age;

    -(void)test
    {
        NSLog(@"_name=%@,_age=%d",_name,_age);
        NSLog(@"name=%@,age=%d",name,age);
        NSLog(@"self->name=%@,self->age=%d",self->name,self->age);
    }

    @end

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            Person *p=[Person new];
            
            p.name=@"wang";
            p.age=21;
            
            NSLog(@" _name:%@ _age:%d",p.name,p.age);
            
            [p test];
    //        我们最后在test方法内部测试了这三种写法的结果,最后结果如下:
    //        _name=(null),_age=0
    //        name=wang,age=21
    //        self->name=wang,self->age=21
    //        显然,name、age和self->name、self->age指的都是使用@synthesize关键字时创建的新变量,他们的值都不是空值
        }
        return 0;
    }


    ———————————————————————————————————————————
    @synthesize的 批量操作 和 指定实例变量的值操作

    上代码:

    #import <Foundation/Foundation.h>

    @interface Person : NSObject
    {
        NSString *_name;
        int _age;
        int _weight;
        int _height;
    }
    @property NSString* name;
    @property int age,weight,height;

    -(void)test;
    @end

    @implementation Person
    @synthesize name=_name;
    @synthesize age=_age,weight=_weight,height=_abc;

    -(void)test
    {
    //      NSLog(@" _name=%@ _age=%d _weight=%d _height=%d",name,age,weight,height);

    //      上面这句话就是错误的了,系统不识别这些实例变量名(name、age、weight、height),错误为:Use of undeclared identifier 'name'; did you mean '_name'?(这里有四个变量,我只在这里写了一个变量的提示错误,其实错误有四个),我们并没有用@synthesize自动为我们设置的实例变量。实质上,当指定实例变量名以后,再不会操作默认的实例变量了。
        
    //    当然,我们可以将上面的其中一个变量做一些小调整,比如 height=_abc;
        NSLog(@" _name=%@ _age=%d _weight=%d _height=%d _abc=%d",_name,_age,_weight,_height,_abc);
    //    显然这里_abc是有数值的,而_height系统是不认识的,因为我们用 @synthesize height=_abc; 操作的是_abc这个实例变量名,而不是_height了
    //    所以说,一句话, @synthesize 方法名 = 实例变量名;  我们实现的是方法,而方法处理什么实例变量是我们自己定义的或者是默认的。
    }
    @end

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
    //        Person *p=[Person new];
    //        p.name=@"wang";
    //        p.age=21;
    //        p.weight=190;
    //        p.height=181;
    //        
    //        NSLog(@" name=%@ age=%d weight=%d height=%d",p.name,p.age,p.weight,p.height);
    //        这句话正常输出。说明了当多个实例变量(成员变量)的数据类型一致的时候,我们可以:
    //        ① @property int age,weight,height; //批量声明set、get方法
    //        ② @synthesize age,weight,height; //批量实现set、get方法
    //        这里要着重说明一点,@property只能是相同类型的实例对象才能批量声明,但是@synthesize可以不同类型的实例对象一起批量实现       
     
    //        接下来是这一部分的一个重点。我们之前知道,在调用关键字@synthesize的时候,我们知道@synthesize会为我们创建一个新的变量进行操作,而这句话 @synthesize 方法名; 其实这里系统是操作默认的实例变量。那么我们能不能利用这个方法去操作指定的实例变量呢?答案当然是肯定的。
    //        代码格式:  @synthesize 方法名 = 实例变量名;
    //        这样,我们就能利用这个方法去操作我们需要操作的实例变量了,例如下面的几行代码,下面的代码是通过设置指定的实例变量名来操作实现get、set方法的
    //        我们是这样指定的:
    //        @synthesize name=_name;
    //        @synthesize age=_age,weight=_weight,height=_height;
            
            Person *p1=[Person new];
            p1.name=@"lao";
            p1.age=21;
            p1.weight=90;
            p1.height=164;
            
    //        NSLog(@" _name=%@ _age=%d _weight=%d _height=%d",p1.name,p1.age,p1.weight,p1.height);
    //        当然直接输出的话,还是应该用调用get方法的方式输出,但是不同之处是,如果我们用一个新的test方法来输出这几个实例变量的名的话,就不太一样了
            [p1 test];
    //        结果如下:
    //        _name=lao
    //        _age=21
    //        _weight=90
    //        _height=0
    //        _abc=164
            
        }
        return 0;
    }


    ———————————————————————————————————————————
    @property增强使用

    在Xcode 4.4之后的版本,我们写实例变量的set、get方法时,可以只写@property 而不写@synthesize。比如说有两个声明了的实例变量(属性成员变量) _name和_age,我们只使用@property关键字的话,那么我们相当于同时声明和实现了_name和_age的set、get方法。(这里是对带有下划线的实例变量名进行操作的,这也是苹果的定义)。而且他的增强还有一点,如果我们在@interface...@end中根本就不声明实例变量的话,那么也可以!只使用@property可以帮我们声明带有下划线的实例变量!(★★★比如说,我写了 @property int age;  那么系统自动声明了一个_age的实例变量,而不用去写 int  _age;   但是要知道的是,这里自动声明的实例对象是私有的,无法被子类  继承  和  访问!!!想要被子类继承,那么还必须在@interface … @end中的大括号内声明这些实例对象!!!★★★)

    上代码:

    #import <Foundation/Foundation.h>

    @interface Person : NSObject
    @property NSString * name;
    @property int age;

    -(void)test;
    @end

    @implementation Person
    -(void)test
    {
        NSLog(@"_name=%@,_age=%d",_name,_age);
        
    //    NSLog(@"name=%@,age=%d",name,age);  显然这句话是错误的,在增强@property中,是只认带有下划线的实例变量的。
    }
    @end

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            Person *p=[Person new];
            p.name=@"wang";
            p.age=21;
            
            [p test];
        }
        return 0;
    }


    ———————————————————————————————————————————
    @property增强使用的一个补充——子类继承问题

    上代码:

    #import <Foundation/Foundation.h>

    @interface Person : NSObject
    //{
    //    NSString *_name;
    //    int _age;
    //}
    //加上这几句声明属性,那么子类就能继承了,但是还是无法访问
    @property NSString * name;
    @property int age;

    -(void)test;
    @end

    @implementation Person
    -(void)test
    {
        NSLog(@"_name=%@,_age=%d",_name,_age);
    //    NSLog(@"_name=%@,_age=%d",self->_name,self->_age); 这句话是和上面一样的
    //    NSLog(@"name=%@,age=%d",name,age);  显然这句话是错误的,在增强@property中,是只认带有下划线的实例变量的。
    }
    @end

    @interface Student : Person
    -(void)test1;
    @end

    @implementation Student
    -(void)test1
    {
    //    NSLog(@" _name=%@ _age=%d",_name,_age);
    //    由于_name和_age这两个实例对象没有声明,只是用@property关键字创建出来的,所以说是相对私有的变量,无法被子类继承和访问,所以上面的这句话是出错的,显示并没有_name和_age的声明。
    //    如果想让这句话正确,那么只需要在@interface ... @end中的大括号里声明即可(但是这样只能做到被继承,但是还是不能被访问,如果访问,需要写@synthesize)

    //    NSLog(@" _a=%d",_a);
    //    在这里我们将_a定义为Person类的@private类型的变量,显示_a只能继承但是不能访问,这里的私有和上面_name/_age的私有还有有一些区别的
    }
    @end

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
    //        Person *p=[Person new];
    //        p.name=@"wang";
    //        p.age=21;
    //        
    //        [p test];
            
            Student *s=[Student new];
            
            s.name=@"lao";
            s.age=21;
            [s test];
    //        这里可能有人会问,为什么我们创建的Student类的实例对象怎么还能调用其父类的set、get方法
    //        那是因为我们将 @property NSString * name;    和    @property int age;   写在了interface里,这是暴露的属性,自然能访问
        }
        return 0;
    }


    ———————————————————————————————————————————
    @property 增强下重写set、get方法

    我们如果使用@property增强去定义变量属性(这里成为方法也可以),那么会出现一些情况,比如过我调用set方法传进来的值不对怎么办?我想稍微改一下set、get方法怎么办。这就需要重写set、get方法。

    重写时有亮点需要注意:
    ①set、get方法只能重写其中的一个,如果两个都重写,编译器会报错的
    ②重写其中一个(set或者get),那么另外一个编译器会自动生成,且重写过的编译器就不会生成默认的了


    ———————————————————————————————————————————

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    noip模拟赛 梦想
    noip模拟赛 水题
    noip模拟赛 猜数字
    Java基础知识强化64:基本类型包装类的引入
    Java基础知识强化63:Arrays工具类之方法源码解析
    Java基础知识强化62:Arrays工具类之概述和使用
    Java基础知识强化61:经典查找之 常见查找算法小结
    Java基础知识强化60:经典查找之二分查找
    Java基础知识强化59:String(字符串)和其他类型的相互转化
    Java基础知识强化58:经典排序之二叉树排序(BinaryTreeSort)
  • 原文地址:https://www.cnblogs.com/wzy294250051/p/4787891.html
Copyright © 2011-2022 走看看