———–Java培训、Android培训、IOS培训、.Net培训、期待与您交流!————
本节是个人学习过程中的笔记,供初学者一起学习,欢迎大家批评指正,留言参与讨论,谢谢。
本节内容,@property和@synthesize的五种类型运用与归纳,
总结了以下几点:
1、@synthesize出现时,服务对象(即为其提供自动方法)为最右侧的那个变量,或者就是唯一存在的那个变量。
2、在接口文件(.h)@interface之后{}大括号外面创建的变量,统一视为不可见,也就是private类型,包括在.m文件中创建的变量。
3、最简单地自动方式:@property type A; 如果 _A未声明,那么这一句话就干三件事,创建 _A,并提供服务。如果 _A已经声明,那么直接提供服务。
4、如果是用户手动+@property自动一起完成set和get,那么后者视为前者提供补充服务。
第三条和第四条,合在一起,就是一种用户行为优先与系统行为的原则。
代码如下:
main.m
//
// main.m
// Test作用域点语法和@property
//
// Created by Mac on 15/4/2.
// Copyright (c) 2015年 Mac. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Pupil.h" // 调用孙子类的.h文件效率最高,虽然import不会重复包含,但是这样写更加简洁
//#import "Person.h"
//#import "Student.h"
//#import "Pupil.h"
// 测试点语法,并且stepinto内部,看清其跳转机制
void testDotGrammer()
{
Person* p = [Person new];
p.age = 10;
int a = p.age;
// 看p.age处于什么位置,对应的.语法,调用对应的set活着get方法。
NSLog(@"p's age is %d",a);
// 下面三行,跳转到@property double weight;这句话中,虽然进不去,但是效果是一样的。
p.weight = 112.3;
double w = p.weight;
NSLog(@"p's weight is %.2f",w);
}
void testVariableArea()
{
Student* s = [Student new];
[s test];
Pupil* p = [Pupil new];
[p test];
}
void testPropertyAndSynthesize()
{
Person* p = [Person new];
// 第一种方式
p.QQNum = 13324;
NSLog(@"QQNum is %d",p.QQNum);
// p._QQNum = 13324;
// NSLog(@"QQNum is %d",p._QQNum);
// p.Num = 13324;
// NSLog(@"QQNum is %d",p.Num);
// 第二种方式
p.msnNum = 15524;
NSLog(@"msnNum is %d",p.msnNum);
// 第三种方式
p.jdNum = 1888;
NSLog(@"jdNum is %d",p.jdNum);
// 第四种方式
p.height = 1333;
NSLog(@"height is %.2f",p.height);
// 第五种方式
p.ccNum = 123;
NSLog(@"ccNum is %d",p.ccNum);
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
testDotGrammer();
testPropertyAndSynthesize();
testVariableArea();
}
return 0;
}
Person.h
//
// Person.h
// Test作用域点语法和@property
//
// Created by Mac on 15/4/2.
// Copyright (c) 2015年 Mac. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
//@protected // 默认项,可以省略
int _age;
int _QQNum;
double _weight;
double _height;
int ccNum;
int _onlyForTest;
@private
int _idNum;
char* _QQPsw;
@public
char* _name;
}
// 传统方式,自己敲冗余代码
- (void)setAge: (int)age;
- (int)age;
@property int idNum;
@property int onlyForTest;
// @property 和 @synthesize 一共好几种使用方式
// 第一种使用方式,最正规的方式
@property int QQNum;
// 下面都是第一种方式的延伸和探究
// @property int _QQNum; // 改成这个样子,也可以执行
// @property int Num; //
// 第二种方式,不创建成员变量,直接用一个新的变量来进行get、set简写
@property int msnNum;
// 第三种方式,不创建成员变量,只用property,不用synthesize
@property int jdNum;
// 创建 _jdNum(私有变量),声明并实现set,get
@property double weight;
// 这种情况类似,只是因为weight已经声明成为protected变量,所以不再是私有变量。
// 第四种方式 程序猿手动实现了set或者get方法,那么系统则优先考虑手动行为,不予创建,只是对其进行补足。这种用户和系统一起完成get、set的方式,不推荐使用,会有警告
//- (void)setHeight: (double)height;
- (double)height;
@property double height;
// 第五种方式,synthesize后面只有唯一一个变量,那么这个变量必须在大括号内声明,而且必须同名
@property int ccNum;
@end
Person.m
//
// Person.m
// Test作用域点语法和@property
//
// Created by Mac on 15/4/2.
// Copyright (c) 2015年 Mac. All rights reserved.
//
#import "Person.h"
@implementation Person
// 传统方式
- (void)setAge: (int)age
{
_age = age;
}
- (int)age
{
return _age;
}
// 第一种方式,最正规的方式
@synthesize QQNum = _QQNum;
// 下面都是第一种方式的延伸和探究
//@synthesize _QQNum = _QQNum;
//@synthesize Num = _QQNum;
// 这种方式也可以,说明,当synthesize存在的时候,以其后面最右边的那个变量为服务对象,只有一个变量的时候,就以那个变量为准。
// 但是这种方式可读性太差,也就失去了价值,只是为了说明synthesize做主的情况
// 第二种方式
@synthesize msnNum = msnNum;
// 这种方式创建并实现setget的变量,是一个私有变量,而是变量名称取决于最右侧。 也正是因为取决于实现部分的synthesize,所以才是私有
// 第三种方式 ,没有synthesize
// 第四种方式 程序猿手动和系统自动一起实现
//- (void)setHeight: (double)height
//{
// _height = height;
//}
- (double)height
{
return _height;
}
// 第五种方式
@synthesize ccNum;
// PS 测试,只有setget,没有声明也没有property去创建的情况
//- (void)setNewer: (int)newer
//{
// _newer = newer; // 这种方式,不行,_newer根本没法定义,所以不能出现,只有set、get,没有对应变量定义的情况
//}
//- (int)newer
//{
// return _newer;
//}
@end
Student.h
//
// Student.h
// Test作用域点语法和@property
//
// Created by Mac on 15/4/2.
// Copyright (c) 2015年 Mac. All rights reserved.
//
#import "Person.h"
@interface Student : Person
- (void)test;
//@property int onlyForTest;
- (void)setOnlyForTest: (int)onlyForTest;
- (int)onlyForTest;
// 对于protected类型变量,子类可以重写么?答案是可以,private变量不行
//@property int idNum;
//- (void)setIdNum: (int)idNum;
//- (void)idNum;
// 以上不管哪种方式,都无法在子类中为父类未曾setget的private变量进行setget设定。
@end
Student.m
//
// Student.m
// Test作用域点语法和@property
//
// Created by Mac on 15/4/2.
// Copyright (c) 2015年 Mac. All rights reserved.
//
#import "Student.h"
@implementation Student
//@synthesize idNum = _idNum;
//- (void)setIdNum: (int)idNum
//{
// self->_idNum = idNum;
//}
//
//- (void)idNum
//{
// return _idNum;
//}
//@synthesize onlyForTest = _onlyForTest;
- (void)setOnlyForTest: (int)onlyForTest
{
_onlyForTest = onlyForTest;
}
- (int)onlyForTest
{
return 8985;
}
- (void)test
{
_QQNum = 10;
// msnNum = 10; // 由于是在大括号外创建的,所以为private类型
//_jdNum = 18;
_weight = 18; // 依然是原本的protected类型
self -> _QQNum = 15;
//self -> _id = 15;
self.idNum = 12;
NSLog(@"idNum is %d",self.idNum);
self.onlyForTest = 999;
NSLog(@"onlyForTest is %d",self.onlyForTest);
}
@end
Pupil.h
//
// Pupil.h
// Test作用域点语法和@property
//
// Created by Mac on 15/4/2.
// Copyright (c) 2015年 Mac. All rights reserved.
//
#import "Student.h"
@interface Pupil : Student
- (void)test;
@end
Pupil.m
//
// Pupil.m
// Test作用域点语法和@property
//
// Created by Mac on 15/4/2.
// Copyright (c) 2015年 Mac. All rights reserved.
//
#import "Pupil.h"
@implementation Pupil
- (void)test
{
_age = 80;
//_id = 33;
// 因为是父类pravite,所以无法访问
// 虽然无法直接访问,
_QQNum = 666666;
// msnNum = 10; // 由于是在大括号外创建的,所以为private类型
//_jdNum = 18;
_weight = 1866666; // 依然是原本的protected类型
self -> _QQNum = 888888;
//self -> _id = 15;
//super -> _id = 32; //能否在子类方法中通过super去直接访问父类的private变量??
// 如果子类全部继承父类的变量,那么在小学生这个子类里面,也应该有隐藏的成员变量,该如何访问
//self -> _id = 123;
// 不管成员变量是什么类型,在外部访问时候都是通过set和get来实现的,体现良好的封装性
}
@end
程序运行结果如下: