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),那么另外一个编译器会自动生成,且重写过的编译器就不会生成默认的了


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

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

  • 相关阅读:
    numpy 基础 —— np.linalg
    图像旋转后显示不完全
    opencv ---getRotationMatrix2D函数
    PS1--cannot be loaded because the execution of scripts is disabled on this system
    打开jnlp Faild to validate certificate, the application will not be executed.
    BATCH(BAT批处理命令语法)
    oracle vm virtualbox 如何让虚拟机可以上网
    merge 实现
    Windows batch,echo到文件不成功,只打印出ECHO is on.
    python2.7.6 , setuptools pip install, 报错:UnicodeDecodeError:'ascii' codec can't decode byte
  • 原文地址:https://www.cnblogs.com/wzy294250051/p/4787891.html
Copyright © 2011-2022 走看看