重学iOS——5.@property的前世今生

96
Peak_One
2017.10.22 23:33* 字数 450

@property是OC中最为常见的关键字之一,实际的项目开发中@property在类中出现的频率甚至达到了100%。但是对于@property的使用规则,你真的完全掌握吗?我觉得我做不到!所以在这里针对@property的相关内容,进行记录,省的将来再学第三遍iOS......

在这里我按照@property的发展顺序进行代码书写,注意点在代码中可以清晰的看到。@property大约是在Xcode4.4的时候提出来的,在此之前,对于类中的属性,我们需要去手动编写繁琐的setter-getter方法。Apple就是为了简化我们的代码编写,所以才引入了@property和@synthesize关键字。

@property诞生之初的基本用法
#Person.h
#import <Foundation/Foundation.h>

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

/*
 setter: 
 作用: 用于给成员变量赋值
 1.一定是对象方法
 2.一定没有返回值
 3.方法名称以set开头, 后面跟上需要赋值的成员变量名称, 并且去掉下划线, 然后首字母大写
 4.一定有参数, 参数类型和需要赋值的成员变量一直, 参数名称就是需要赋值的成员变量名称去掉下划线
 */
//- (void)setAge:(int)age;
- (void)setHeight:(double)height;
- (void)setWeight:(double)weight;
- (void)setName:(NSString *)name;

/*
@porperty是一个编译器指令
 在Xocde4.4之前, 可以使用@porperty来代替getter/setter方法的声明
 也就是说我们只需要写上@porperty就不用写getter/setter方法的声明
 
 编译器只要看到@property, 就知道我们要生成某一个属性的getter/setter方法的声明
 
 - (void)setAge:(int)age;
 - (int)age;
 */
@property int age;

/*
 - (void)set_age:(int)_age;
 - (int)_age;
 */
@property int _age;

/*
 getter:
 作用: 用于获取成员变量的值
 1.一定是对象方法
 2.一定有返回值, 返回值类型和需要获取的成员变量的类型一致
 3.方法名称就是需要获取的成员变量的名称去掉下划线
 4.一定没有参数
 */
//- (int)age;
- (double)height;
- (double)weight;
- (NSString *)name;

@end
#Person.m
#import "Person.h"

@implementation Person
- (void)setAge:(int)age
{
    _age = age;
}
- (void)setHeight:(double)height
{
    _height = height;
}

- (void)setWeight:(double)weight
{
    _weight = weight;
}
- (void)setName:(NSString *)name
{
    _name = name;
}


- (int)age
{
    return _age;
}
- (double)height
{
    return _height;
}
- (double)weight
{
    return _weight;
}
- (NSString *)name
{
    return _name;
}
@end
@synthesize的基本用法

说过了@property的最初是用法,我们不得不提一下@synthesize这个关键字,Apple在最初设计@property之初,为了与@property相照应,完成完善的setter-getter方法,引入了@synthesize,因为在最初的设计中,@property只负责setter-getter方法的生命,而没有setter-getter方法的实现,所以引入了@synthesize,具体用法如下:

#Person.h
#import <Foundation/Foundation.h>

@interface Person : NSObject
{
    @public
    int _age;
    int age;
    int _number;
}

/*
@porperty是一个编译器指令
 在Xocde4.4之前, 可以使用@porperty来代替getter/setter方法的声明
 也就是说我们只需要写上@porperty就不用写getter/setter方法的声明
 
 编译器只要看到@property, 就知道我们要生产某一个属性的getter/setter方法的声明
 
 - (void)setAge:(int)age;
 - (int)age;
 */
@property int age;

@end
#Person.m

#import "Person.h"

@implementation Person

/*
 @synthesize是一个编译器指令, 它可以简化我们getter/setter方法的实现
 
 什么是实现:
 在声明后面写上大括号就代表着实现
 
 1.在@synthesize后面告诉编译器, 需要实现哪个@property生成的声明
 2. 告诉@synthesize, 需要将传入的值赋值给谁和返回谁的值给调用者
 
 - (void)setAge:(int)age
 {
    _age = age;
 }
 - (int)age
 {
    return _age;
 }
 */
//@synthesize age = _age;

/*
 - (void)setAge:(int)age
 {
    _number = age;
 }
 - (int)age
 {
    return _number
 ;
 }
 */
//@synthesize age = _number;


// 如果在@synthesize后面没有告诉系统将传入的值赋值给谁, 系统默认会赋值给和@synthesize后面写得名称相同的成员变量
// _age? age;
@synthesize age;

/*
- (void)setAge:(int)age
{
    _age = age;
}

- (int)age
{
    return _age;
}
 */

@end
#mian.m
#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
    Person *p = [Person new];
    [p setAge:88];
//    NSLog(@"age = %i , p->_age = %i", [p age], p->_age);
//    NSLog(@"_age = %i, _number = %i", p->_age, p->_number);
    NSLog(@"_age = %i, age = %i", p->_age, p->age);
    
    return 0;
}
@porperty功能的增强

看完前面的例子,我们不难分析出,为什么会蹩脚的提出@property和@synthesize,而不是将两个功能集成到一个关键字呢?同样也是出于这方面考虑,Apple对@property进行了功能增强,具体代码如下:

#Person.h

#import <Foundation/Foundation.h>

@interface Person : NSObject
/*
{
    @public
    int _age;
    int age;
}
 
 */

/*
 从Xcode4.4以后apple对@property进行了一个增强, 以后只要利用一个@property就可以同时生成setter/getter方法的声明和实现
 没有告诉@property要将传入的参数赋值给谁, 默认@property会将传入的属性赋值给_开头的成员变量
 
 @property有一个弊端: 它只会生成最简单的getter/setter方法的声明和实现, 并不会对传入的数据进行过滤
 如果想对传入的数据进行过滤, 那么我们就必须重写getter/setter方法
 如果不想对传入的数据进行过滤, 仅仅是提供一个方法给外界操作成员变量, 那么就可以使用@property
 
 如果利用@property来生成getter/setter方法, 那么我们可以不写成员变量, 系统会自动给我们生成一个_开头的成员变量
 注意: @property自动帮我们生成的成员变量是一个私有的成员变量, 也就是说是在.m文件中生成的, 而不是在.h文件中生成的
 */
// age? _age;
/*
 - (void)setAge:(int)age;
 - (int)age;
 */
@property int age;

@end
#Person.m
#import "Person.h"

@implementation Person

/*
 - (void)setAge:(int)age
 {
    _age = age;
 }
 - (int)age
 {
    return _age;
 }
 */

// 如果重写了setter方法, 那么property就只会生成getter方法
// 如果重写了getter方法, 那么property就只会生成setter方法
// 如果同时重写了getter/setter方法, 那么property就不会自动帮我们生成私有的成员变量
- (void)setAge:(int)age
{
    if (age < 0) {
        age = 0;
    }
    _age = age;
}

//- (int)age
//{
//    return _age;
//}
@end
#mian.m
#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
    Person *p = [Person new];
    [p setAge:-88];
//    NSLog(@"age = %i", [p age]);
//    NSLog(@"_age = %i, age = %i", p->_age, p->age);
    return 0;
}
@porperty修饰符
#Person.h
#import <Foundation/Foundation.h>

@interface Person : NSObject

/*
 如果给一个属性同时提供了getter/setter方法, 那么我们称这个属性为可读可写属性
 如果只提供了getter方法, 那么我们称这个属性为只读属性
 如果只提供了setter方法, 那么我们称这个属性为只写属性
 如果既没有提供getter也没有提供setter方法, 那么我们称这个属性为私有属性
 
 
 格式:
 @property(属性修饰符) 数据类型 变量名称;
 */
// readwrite: 代表既生成getter方法 , 也生成setter方法
// 默认情况下 @property就是readwrite的
@property(readwrite) int age;
/*
 - (void)setHeight:(double)height;
 - (double)height;
 
 - (void)setHeight:(double)height;
 - (double)abc;
 */
@property(getter=abc) double height;

/*
 - (void)setWeight:(double)weight;
 - (void)tiZhong:(double)weight;
 */
@property(setter=tiZhong:) double weight;
// readonly: 代表只生成getter方法不生成setter方法
@property(readonly) NSString * name;

// 是否已婚
// 程序员之间有一个约定, 一般情况下获取BOOL类型的属性的值, 我们都会将获取的方法名称改为isXXX
@property(getter=isMarried) BOOL married;
@end
#Person.m
#import "Person.h"

@implementation Person

@end
#mian.m
#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {

    Person *p = [Person new];
//    p.age = 30;
//    p.name = @"猪立叶";
//    p.height = 1.88;
//    p.weight = 200.0;
//    [p setName:@"lnj"];
    p.height = 99;
    NSLog(@"height = %f", [p abc]);

    [p tiZhong:100.0];
    NSLog(@"weight = %f", [p weight]);
    
    [p setMarried:YES];
    /*
    if ([p married]) {
        NSLog(@"已婚");
    }else
    {
        NSLog(@"未婚");
    }
     */
    
    if ([p isMarried]) {
        NSLog(@"已婚");
    }else
    {
        NSLog(@"未婚");
    }
    return 0;
}

欢迎关注我的个人微信公众号,免费送计算机各种最新视频资源!你想象不到的精彩!


0.jpg
iOS成行之路