在學(xué)習(xí)Runtime的過程中,自己對objc_ivar中ivar_offset的作用不太理解,所以自己建立了一個工程來研究理解。ivar_offset是指內(nèi)存偏移量,即該成員變量對于該對象的內(nèi)存地址偏移了多少,setter和getter方法均會根據(jù)此地址來改變該成員屬性,那么如果是繼承自一個父類,該成員變量的地址又會有什么變化呢?
我們新建兩個類,father和son,father繼承自NSObject,son繼承自father。
1.先讓son有一個數(shù)組屬性,叫做girls:
#import "Father.h"
@interface Son : Father
@property (nonatomic, strong) NSArray *girls;
@end
2.然后我們利用Runtime技術(shù)打印該變量的偏移量:
#import "ViewController.h"
#import <objc/message.h>
#import "Son.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
Ivar var_instance_girls = class_getInstanceVariable([Son class], "_girls");
ptrdiff_t offset_var_girls = ivar_getOffset(var_instance_girls);
NSLog(@"Grils Offset:%td", offset_var_girls);
}
控制臺的結(jié)果如下:
Grils Offset:8
偏移結(jié)果為8,正對應(yīng)64-bit系統(tǒng)下一個對象指針為8字節(jié)。
3.然后我們給son添加另外一個數(shù)組屬性叫做cars,然后打印cars的offset:
son:
#import "Father.h"
@interface Son : Father
@property (nonatomic, strong) NSArray *girls;
@property (nonatomic, strong) NSArray *cars;
@end
viewcontroller:
#import "ViewController.h"
#import <objc/message.h>
#import "Son.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
Ivar var_instance_girls = class_getInstanceVariable([Son class], "_girls");
ptrdiff_t offset_var_girls = ivar_getOffset(var_instance_girls);
NSLog(@"Grils Offset:%td", offset_var_girls);
Ivar var_instance_cars = class_getInstanceVariable([Son class], "_cars");
ptrdiff_t offset_var_cars = ivar_getOffset(var_instance_cars);
NSLog(@"Cars Offset:%td", offset_var_cars);
}
@end
此時,打印結(jié)果如下:
Grils Offset:8
Cars Offset:16
這說明新增的成員變量又偏移了一個成員指針的大小,放在前一個成員變量的后面。那么假如father類新增一個成員變量,那么son的成員變量的offset會發(fā)生什么變化呢?
4.我們給father增加一個成員變量叫做money:
#import <Foundation/Foundation.h>
@interface Father : NSObject
@property (nonatomic, strong) NSArray *money;
@end
然后打印son的money屬性的offset:
#import "ViewController.h"
#import <objc/message.h>
#import "Son.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
Ivar var_instance_girls = class_getInstanceVariable([Son class], "_girls");
ptrdiff_t offset_var_girls = ivar_getOffset(var_instance_girls);
NSLog(@"Grils Offset:%td", offset_var_girls);
Ivar var_instance_cars = class_getInstanceVariable([Son class], "_cars");
ptrdiff_t offset_var_cars = ivar_getOffset(var_instance_cars);
NSLog(@"Cars Offset:%td", offset_var_cars);
Ivar var_instance_money = class_getInstanceVariable([Son class], "_money");
ptrdiff_t offset_var_money = ivar_getOffset(var_instance_money);
NSLog(@"Money Offset:%td", offset_var_money);
}
@end
此時,打印結(jié)果如下:
Grils Offset:16
Cars Offset:24
Money Offset:8
我們發(fā)現(xiàn),father新添的成員變量money被排在了第一個位置,而son中的成員變量grils和cars均被向后偏移了。而這正是繼承關(guān)系應(yīng)該有的情況。子類繼承父類,當(dāng)然是要優(yōu)先將父類的成員變量放到前面,然后再添加子類的,這樣層層繼承下去僅需根據(jù)offset的值就能直接使用父類或自己的成員變量了。