面试题:
1.OC的消息机制
析:
OC中的方法调用其实都是转成objc_msgSend函数的调用,给receiver(方法调用者)发送一条消息(selector方法名)
objc_msgSend底层有3大阶段:消息转发(当前类、父类中查找)、动态方法解析、消息转发
2.什么是runtime?平时项目中有用过?
析:
OC是一门动态性比较强的编程语言,允许很多操作推迟到程序运行时再进行
OC的动态性就是Runtime来支撑和实现的,Runtime是一套C语言的API,封装了很多动态性相关的函数
平时编写的OC代码,底层都是转换成了RuntimeAPI进行调用
3.具体应用
析:
l.利用关联对象(AssociatedObject)给分类添加属性
2.遍历类的所有成员变量(修改textFiled的占位文字颜色、字典转模型、自动归档解档)
3.交换方法实现(交换系统的 方法)
4.利用消息转发机制解决方法找不到的异常问题
5. ...
本文Demo代码见gitHubDemo
补充:
1.&可以用来取出特定的位 (取值)
0000 0111
&0000 0100
------------
0000 0100
2.宏定义【掩码,一般用来按位与(&)运算的】
#define myA 1
#define myB 2
#define myC 4
改进:
#define myA 0b00000001
#define myB 0b00000010
#define myC 0b00000100
最终改良版:
#define myA (1<<0)
#define myB (1<<1)
#define myC (1<<2)
需求:将对象里面的tall,rich,handsome放在一个字节里面(char)
myPerson.h
#import <Foundation/Foundation.h>
@interface myPerson : NSObject
- (void)setTall:(BOOL)tall;
- (void)setRich:(BOOL)rich;
- (void)setHandsome:(BOOL)handsome;
- (BOOL)isTall;
- (BOOL)isRich;
- (BOOL)isHandsome;
@end
myPerson.m
#import "myPerson.h"
#define myTallMask (1<<0)
#define myRichMask (1<<1)
#define myHandsomeMask (1<<2)
@interface myPerson(){
char _tallRichHansome;
}
@end
@implementation myPerson
- (instancetype)init{
if (self = [super init]) {
_tallRichHansome = 0b00000100; //tall 0 , rich 0 , handsome 1
}
return self;
}
- (void)setTall:(BOOL)tall{
if (tall) {
_tallRichHansome |= myTallMask; //设位为1值(或运算 要运算的那位为1,其他的为0)
//0b **** **** | 0b 0000 0001 => 0b **** ***1
} else {
_tallRichHansome &= ~myTallMask; //设位为0值(与运算 要运算的那位为0,其他的为1)
//0b **** **** & 0b 1111 1110 => 0b **** ***0
}
}
- (BOOL)isTall{
return !!(_tallRichHansome & myTallMask);
//0b **** ***X & 0b 0000 0001 ==> 0b 0000 000X
}
- (void)setRich:(BOOL)rich{
if (rich) {
_tallRichHansome |= myRichMask;
} else {
_tallRichHansome &= ~myRichMask;
}
}
- (BOOL)isRich{
return !!(_tallRichHansome & myRichMask);
}
- (void)setHandsome:(BOOL)handsome{
if (handsome) {
_tallRichHansome |= myHandsomeMask;
} else {
_tallRichHansome &= ~myHandsomeMask;
}
}
- (BOOL)isHandsome{
return !!(_tallRichHansome & myHandsomeMask);
}
@end
【main】
myPerson *person = [[myPerson alloc] init];
person.rich = YES;
person.tall = NO;
person.handsome = YES;
NSLog(@"tall:%d rich:%d hansome:%d", person.isTall, person.isRich, person.isHandsome);
打印:tall:0 rich:1 hansome:1
位域
myPerson.h
#import <Foundation/Foundation.h>
@interface myPerson : NSObject
- (void)setTall:(BOOL)tall;
- (void)setRich:(BOOL)rich;
- (void)setHandsome:(BOOL)handsome;
- (BOOL)isTall;
- (BOOL)isRich;
- (BOOL)isHandsome;
@end
myPerson.m
#import "myPerson.h"
@interface myPerson(){
// 位域
struct {
char tall : 1;//占一位(倒数第一位)
char rich : 1;//占一位(倒数第二位)
char handsome : 1;//占一位 (倒数第三位)
} _tallRichHandsome; // 0b0000 0000
}
@end
@implementation myPerson
- (void)setTall:(BOOL)tall{
_tallRichHandsome.tall = tall;
}
- (BOOL)isTall{
return !!_tallRichHandsome.tall;
}
- (void)setRich:(BOOL)rich{
_tallRichHandsome.rich = rich;
}
- (BOOL)isRich{
return !!_tallRichHandsome.rich;
}
- (void)setHandsome:(BOOL)handsome{
_tallRichHandsome.handsome = handsome;
}
- (BOOL)isHandsome{
return !!_tallRichHandsome.handsome;
}
@end
【main】
myPerson *person = [[myPerson alloc] init];
person.rich = YES;
person.tall = NO;
person.handsome = YES;
NSLog(@"tall:%d rich:%d hansome:%d", person.isTall, person.isRich, person.isHandsome);
打印:tall:0 rich:1 hansome:1
共同体(类似苹果官方做法)
myPerson.h
@interface myPerson : NSObject
- (void)setTall:(BOOL)tall;
- (BOOL)isTall;
- (void)setRich:(BOOL)rich;
- (BOOL)isRich;
- (void)setHandsome:(BOOL)handsome;
- (BOOL)isHandsome;
- (void)setThin:(BOOL)thin;
- (BOOL)isThin;
@end
myPerson.m
#import "myPerson.h"
#define myTallMask (1<<0)
#define myRichMask (1<<1)
#define myHandsomeMask (1<<2)
#define myThinMask (1<<3)
@interface myPerson(){
union {
int bits;
struct {
char tall : 1;
char rich : 1;
char handsome : 1;
char thin : 1;
};//仅仅是增加可读性,可删除
} _tallRichHandsome;
}
@end//如果不止4位了,那么不够了就改 int 类型了
@implementation myPerson
- (void)setTall:(BOOL)tall{
if (tall) {
_tallRichHandsome.bits |= myTallMask;
} else {
_tallRichHandsome.bits &= ~myTallMask;
}
}
- (BOOL)isTall{
return !!(_tallRichHandsome.bits & myTallMask);
}
- (void)setRich:(BOOL)rich{
if (rich) {
_tallRichHandsome.bits |= myRichMask;
} else {
_tallRichHandsome.bits &= ~myRichMask;
}
}
- (BOOL)isRich{
return !!(_tallRichHandsome.bits & myRichMask);
}
- (void)setHandsome:(BOOL)handsome{
if (handsome) {
_tallRichHandsome.bits |= myHandsomeMask;
} else {
_tallRichHandsome.bits &= ~myHandsomeMask;
}
}
- (BOOL)isHandsome{
return !!(_tallRichHandsome.bits & myHandsomeMask);
}
- (void)setThin:(BOOL)thin{
if (thin) {
_tallRichHandsome.bits |= myThinMask;
} else {
_tallRichHandsome.bits &= ~myThinMask;
}
}
- (BOOL)isThin{
return !!(_tallRichHandsome.bits & myThinMask);
}
@end
【main】
myPerson *person = [[myPerson alloc] init];
person.rich = YES;
person.tall = NO;
person.handsome = YES;
NSLog(@"tall:%d rich:%d hansome:%d", person.isTall, person.isRich, person.isHandsome);
打印:tall:0 rich:1 hansome:1
isa详解/位域
- isa详解
- 要想学习runtime,首先要了解它底层的一些常用数据结构,比如isa指针
- 在arm64架构之前,isa就是一个普通的指针,存储着Class、Meta-Class对象的内存地址
-
从arm64架构之后,对isa进行了优化,变成一个共同体(union)结构,还使用位域来存储更多的信息
runtime_01.png
根据上面2图 :整合如下(arm64)
union isa_t {
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits;
struct {
uintptr_t nonpointer : 1;
uintptr_t has_assoc : 1;
uintptr_t has_cxx_dtor : 1;
uintptr_t shiftcls : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/
uintptr_t magic : 6;
uintptr_t weakly_referenced : 1;
uintptr_t deallocating : 1;
uintptr_t has_sidetable_rc : 1;
uintptr_t extra_rc : 19
};
};
总共:1+1+1+33+6+1+1+1+19 = 64 位
说明:(isa位域)
1.nonpointer
0:代表普通的指针,存储着Class、Meta-Class对象的内存地址
1:代表优化过,使用位域存储更多的信息
2.has_assoc
是否有设置过关联对象,如果没有,释放时会更快
3.has_cxx_dtor
是否有C++的析构函数(.cxx_destruct),如果没有释放时会更快
4.shiftcls
存储着Class、Meta-Class对象的内存地址信息
5.magic
用于在调试时分辨对象是否未完成初始化
6.weakly_referenced
是否有被弱引用指向过,如果没有,则释放时会更快
7.deallocating
对象是否正在释放
8.has_sidetable_rc
引用计数器是否过大无法存储在isa中
如果为1,那么引用计数会存储在一个叫SideTable的类的属性中
9.extra_rc
里面存储的值是引用计数器减1
枚举或
myPerson.h
#import <Foundation/Foundation.h>
typedef enum {
OptionsOne = 1<<0, // 0b 0000 0001
OptionsTwo = 1<<1, // 0b 0000 0010
OptionsThree = 1<<2,//0b 0000 0100
OptionsFour = 1<<3 // 0b 0000 1000
} Options;
@interface myPerson : NSObject
@property(nonatomic,assign)Options option;
@end
myPerson.m
#import "myPerson.h"
@implementation myPerson
-(void)setOption:(Options)option{
if (option & OptionsOne) {
NSLog(@"包含了OptionsOne");
}
if (option & OptionsTwo) {
NSLog(@"包含了OptionsTwo");
}
if (option & OptionsThree) {
NSLog(@"包含了OptionsThree");
}
if (option & OptionsFour) {
NSLog(@"包含了OptionsFour");
}
}
@end
【main】
#import <Foundation/Foundation.h>
#import "myPerson.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
myPerson *p = [[myPerson alloc]init];
p.option = OptionsOne | OptionsTwo | OptionsThree | OptionsFour;
}
return 0;
}
友情链接:
网友评论