心得一.使用 objc_msgSend 强制转换类型(以下两种方式):
1.NSString *(*fn)(id, SEL, NSString *) = (NSString *(*)(id, SEL, NSString *))objc_msgSend;
fn(self, @selector(method1:), @"呵呵");
2.((uint16_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter);
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
// - 调用 IMP 方法
IMP result7 = class_getMethodImplementation([ViewController class], @selector(method0:));
int (*px)(id, SEL, NSString *) = (int (*)(id, SEL, NSString *))result7;
// - 下边的两种写法都可以
1. px(nil, nil, @"ssss"); 2. px(self, @selector(method0:), @"ssss");
// - 设置一个a类型的对象为 b类型的对象 这是后如果 a,b同时有 eat 方法 [a eat]会调用 b 类中 的 eat 方法
object_setClass(id a, Class [b class]);
// - method_setImplementation 和 method_getImplementation 用于交换法方法的实现 这时候调用 [a eat] 实际上会调用 [b eat]的方法的实现(用于方法交换超级好用, 比MethodSwizzle 牛逼多了)
Method mMethod = class_getInstanceMethod([a class], @selector(eat));
Method impMethod = class_getInstanceMethod([b class], @selector(eat));
IMP imp = method_getImplementation(impMethod)
method_setImplementation(mMethod, imp);
// - OC 数据类型和 void* 互转
Person *person = [[Person alloc]init];
void *vp = (__bridge void*)person;
__unsafe_unretained Person *person = (__bridge Person *)vp;
// - 用 runtime 和 KVC 修改 基本数据类型的值
int age = 30;
// - 使用 KVC 修改基本数据类型的值
[person setValue:@(100) forKey:@"age"];
// - 使用 runtime 修改基本数据类型的值
int age = 10;
Ivar i = class_getInstanceVariable([person class], "_age");
// - 下边两个效果是一样的 只是上边的有警告, 所以使用下边的方法
object_setIvar(person, i, (__bridge id)(void *)age);
object_setIvar(person, i, (__bridge id)(*((void **)&age)));
// - C语言修改
/**1. 使用 ivar_getOffset 获取非指针类型的数据 */
ptrdiff_t ageOffset = ivar_getOffset(class_getInstanceVariable(person.class, "_age"));
int *ageP = (int *)(person + ageOffset);
*ageP = 10;
/** 使用2. ivar_getOffset 修改指针类型的数据 */
ptrdiff_t nameOffset = ivar_getOffset(class_getInstanceVariable(person.class, "_name"));
void **namePP = (void **)(vp + nameOffset);
*namePP = @"WXC";
/** 使用3. ivar_getOffset 获取指针类型的数据 */
ptrdiff_t sonOffset = ivar_getOffset(class_getInstanceVariable(person.class, "_son"));
void **sonPP = (void **)(person + sonOffset);
*sonPP = (__bridge_retained void *)son;
心得二.字符串扫描器:
// - type = @"@\"NSString\"";
@property (nonatomic, copy, readonly) NSString *name;
// - type = @"@\"<UIKeyInput><UIPickerViewDelegate><UITextSelecting>\"";
@property (nonatomic, strong) id <UIKeyInput, UIPickerViewDelegate, UITextSelecting> testAnyProp;
// - type = @"@\"NSString<UITabBarDelegate><UINavigationBarDelegate>\"";
@property (nonatomic, strong) NSString <UITabBarDelegate, UINavigationBarDelegate> *testAny1Prop;
if ((type & YYEncodingTypeMask) == YYEncodingTypeObject && _typeEncoding.length) {
NSScanner *scanner = [NSScanner scannerWithString:_typeEncoding];
if (![scanner scanString:@"@\"" intoString:NULL]) continue;
NSString *clsName = nil;
if ([scanner scanUpToCharactersFromSet: [NSCharacterSet characterSetWithCharactersInString:@"\"<"] intoString:&clsName]) {
if (clsName.length) _cls = objc_getClass(clsName.UTF8String);
}
NSMutableArray *protocols = nil;
while ([scanner scanString:@"<" intoString:NULL]) {
NSString* protocol = nil;
if ([scanner scanUpToString:@">" intoString: &protocol]) {
if (protocol.length) {
if (!protocols) protocols = [NSMutableArray new];
[protocols addObject:protocol];
}
}
[scanner scanString:@">" intoString:NULL];
}
_protocols = protocols;
}
心得三: 信号量的使用
static dispatch_semaphore_t lock;
dispatch_once(&onceToken, ^{
lock = dispatch_semaphore_create(1);
});
dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
// - do someting ...
dispatch_semaphore_signal(lock);