赞
踩
1、【动态语言】:Objective-C语言(以下简称“OC”)是一门动态语言,其优势有:代码编程更灵活,如可以将消息转成给我们想要的对象,或者随意交换一个方法的实现等。
2、【编译器 + 运行时操作系统】:OC作为动态语言,其需要编译器和运行时系统来执行编译的代码,而这个运行时系统就是我所要讲的Objc Runtime(Runtime)。Runtime本身是一个库,它基本上是用C和汇编写的,有了这个库使得C语言有面向对象的能力。
3、【函数的调用区别】:C语言,在编译的时候决定调用哪个函数;OC语言,在运行的时候决定调用哪个函数。
4、【在编译阶段报错】:OC可以调用任何函数,即使这个函数并未实现,只要声明过就不会报错;C语言调用未实现的函数就会报错。
#import<objc/runtime.h> : //成员变量,类,方法
class_copyIvarList : 获得某个类内部的所有成员变量
class_copyMethodList : 获得某个类内部的所有方法
class_getInstanceMethod : 获得某个具体的实例方法 (对象方法,减号-开头)
class_getClassMethod : 获得某个具体的类方法 (加号+开头)
method_exchangeImplementations : 交换两个方法的实现
#import<objc/message.h> : //消息机制
objc_msgSend(...)
#import <Foundation/Foundation.h>
@interface ZMPerson : NSObject
/** 姓名 **/
@property (nonatomic, copy) NSString *name;
/** 性别 **/
@property (nonatomic, copy) NSString *sex;
- (NSString *)coding;
- (NSString *)eating;
- (NSString *)changeMethod;
@end
#import "ZMPerson.h"
#import <objc/runtime.h>
@interface ZMPerson(){
NSString *mobile;//手机号
}
/** 年龄 **/
@property (nonatomic, copy) NSString *age;
@end
@implementation ZMPerson{
NSString *address;//地址
}
- (NSString *)coding {
return @"coding";
}
- (NSString *)eating {
return @"eating";
}
- (NSString *)changeMethod {
return @"方法已被拦截并替换";
}
// void(*)()
// 默认方法都有两个隐式参数,
void eat(id self, SEL _cmd, NSNumber *meter){
NSLog(@"%@ __ %@ __ %@",[self class],NSStringFromSelector(_cmd),meter);
}
// 当一个对象调用未实现的方法,会调用这个方法处理,并且会把对应的方法列表传过来.
// 刚好可以用来判断,未实现的方法是不是我们想要动态添加的方法
+ (BOOL)resolveInstanceMethod:(SEL)sel{
NSString *selStr = @"eat:";
SEL selFromStr = NSSelectorFromString(selStr);
if (sel == selFromStr) {
// 动态添加eat方法
// 第一个参数:给哪个类添加方法
// 第二个参数:添加方法的方法编号
// 第三个参数:添加方法的函数实现(函数地址)
// 第四个参数:函数的类型,(返回值+参数类型) v:void @:对象->self :表示SEL->_cmd
class_addMethod(self, sel, (IMP)eat, "v@:@");
}
return [super resolveInstanceMethod:sel];
}
@end
#import "ZMPerson.h"
@interface ZMFirstVC ()
@property (nonatomic, strong) ZMPerson *person;
@end
@implementation ZMFirstVC
- (void)initView {
[super initView];
_person = [ZMPerson new];
}
- (void)buttonClick:(UIButton *)sender {
// ------ 设置属性值 -----
_person.sex = @"1";
unsigned int count = 0;
// 动态获取类中的所有属性(包括私有)
Ivar *ivar = class_copyIvarList(_person.class, &count);
// 遍历属性找到对应字段
for (int i = 0; i < count; i ++) {
Ivar tempIvar = ivar[i];
//ivar_getName:将IVar变量转化为字符串
const char *varChar = ivar_getName(tempIvar);
//ivar_getTypeEncoding:获取IVar的类型
//const char *memberType = ivar_getTypeEncoding(tempIvar);
NSString *varString = [NSString stringWithUTF8String:varChar];
if ([varString isEqualToString:@"_name"]) {
// 修改对应的字段值
object_setIvar(_person, tempIvar, @"姓名");
}
NSLog(@"----->%@",varString);
//私有类
if ([varString isEqualToString:@"_age"]) {
object_setIvar(_person, tempIvar, @"100");
}
//私有类
if ([varString isEqualToString:@"address"]) {
object_setIvar(_person, tempIvar, @"福建省厦门市");
}
//私有类
if ([varString isEqualToString:@"mobile"]) {
object_setIvar(_person, tempIvar, @"138****8888");
}
}
// ---- 利用KVC键值编码 获取属性值 -----
NSString *str0 = [_person valueForKey:@"_name"];
NSString *str1 = [_person valueForKey:@"_sex"];
NSString *str2 = [_person valueForKey:@"_age"];
NSString *str3 = [_person valueForKey:@"address"];
NSString *str4 = [_person valueForKey:@"mobile"];
NSMutableString *mstr = [NSMutableString string];
[mstr appendString:str0];
[mstr appendString:str1];
[mstr appendString:str2];
[mstr appendString:str3];
[mstr appendString:str4];
NSLog(@"非私有类:%@__%@\n私有类:%@__%@__%@__",str0,str1,str2,str3,str4);
self.testLabelText = mstr ? mstr : @"更改属性值失败";
// ----- 键值编码设置属性值 ------
[_person setValue:@"我的家乡还是在福建啊" forKey:@"address"];
NSLog(@"=======%@", [_person valueForKey:@"address"]);
}
@end
执行结果:
#import <Foundation/Foundation.h>
@interface NSObject (ZMAddAttribute_h)
@property (nonatomic, copy) NSString *name;
@end
#import "NSObject+ZMAddAttribute_h.h"
#import <objc/message.h>
@implementation NSObject (ZMAddAttribute_h)
-(void)setName:(NSString *)name{
objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSString *)name{
return objc_getAssociatedObject(self, @"name");
}
@end
#import "NSObject+ZMAddAttribute_h.h"
@interface ZMSecondVC ()
@property (nonatomic, strong) NSObject *person;
@end
@implementation ZMSecondVC
- (void)initView {
[super initView];
_person = [NSObject new];
_person.name = @"添加属性成功";
}
- (void)buttonClick:(UIButton *)sender {
self.testLabelText = _person.name.length ? _person.name : @"添加属性失败";
}
@end
#import "ZMPerson.h"
@interface ZMThirdVC ()
@property (nonatomic, strong) ZMPerson *person;
@end
@implementation ZMThirdVC
- (void)initView {
[super initView];
_person = [ZMPerson new];
}
- (void)buttonClick:(UIButton *)sender {
/*
动态添加 coding 方法
(IMP)codingOC 意思是 codingOC 的地址指针;
"v@:" 意思是,v 代表无返回值 void,如果是 i 则代表 int;@代表 id sel; : 代表 SEL _cmd;
“v@:@@” 意思是,两个参数的没有返回值。
*/
class_addMethod([_person class], @selector(test), (IMP)codingObjC, "v@:");
// 调用 coding 方法响应事件
if ([_person respondsToSelector:@selector(test)]) {
[_person performSelector:@selector(test)];
self.testLabelText = @"添加方法成功";
}else{
self.testLabelText = @"添加方法失败";
}
[_person performSelector:@selector(eat:) withObject:@100 afterDelay:3];
}
-(void)test{
NSLog(@"测试测试");
}
// 方法实现
void codingObjC(id self,SEL _cmd){
NSLog(@"添加方法成功");
}
@end
#import "ZMPerson.h"
@interface ZMFourthVC ()
@property (nonatomic, strong) ZMPerson *person;
@end
@implementation ZMFourthVC
- (void)initView {
[super initView];
_person = [ZMPerson new];
NSLog(@"%@",_person.coding);
NSLog(@"%@",_person.eating);
}
- (NSArray *)buttonTitleArray {
return @[@"交换", @"不交换"];
}
- (void)buttonClick:(UIButton *)sender {
if (sender.tag == 0) {
[self exchangeMethod];
}
NSString *str = [NSString stringWithFormat:@"%@_%@",[_person coding],[_person eating]];
self.testLabelText = str;
NSLog(@"%@",_person.coding);
NSLog(@"%@",_person.eating);
}
///交换方法
-(void)exchangeMethod{
Method aMethod = class_getInstanceMethod([_person class], @selector(coding));
Method bMethod = class_getInstanceMethod([_person class], @selector(eating));
method_exchangeImplementations(aMethod, bMethod);
}
#import <objc/runtime.h>
@interface NSObject (Swizzle)
///拦截替换方法
+ (BOOL)swizzleMethod:(SEL)origSel withMethod:(SEL)aftSel;
@end
@implementation NSObject (Swizzle)
///拦截替换方法
+ (BOOL)swizzleMethod:(SEL)origSel withMethod:(SEL)aftSel {
Method originMethod = class_getInstanceMethod(self, origSel);
Method newMethod = class_getInstanceMethod(self, aftSel);
if(originMethod && newMethod) {//必须两个Method都要拿到
if(class_addMethod(self, origSel, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) {
//实现成功添加后
class_replaceMethod(self, aftSel, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
}
return YES;
}
return NO;
}
@end
#import "NSObject+Swizzle.h"
@implementation MyString
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = object_getClass((id)self);
[class swizzleMethod:@selector(resolveInstanceMethod:) withMethod:@selector(myResolveInstanceMethod:)];
});
}
+ (BOOL)myResolveInstanceMethod:(SEL)sel {
if(! [self myResolveInstanceMethod:sel]) {
// NSString *selString = NSStringFromSelector(sel);
// class_addMethod(self, sel, class_getMethodImplementation(self, @selector(dynamicMethodIMP)), "v@:");
// return YES;
NSString *selString = NSStringFromSelector(sel);
///锁定一些方法如果不存在则创建
if([selString isEqualToString:@"countAll"] || [selString isEqualToString:@"pushViewController"] || [selString isEqualToString:@"test"]) {
class_addMethod(self, sel, class_getMethodImplementation(self, @selector(dynamicMethodIMP)), "v@:");
return YES;
}else {
return NO;
}
}
return YES;
}
- (void)dynamicMethodIMP {
NSLog(@"我是动态加入的函数");
}
- (void)buttonClick:(UIButton *)sender {
NSLog(@"begin test");
MyString *string = [[MyString alloc] init];
[string performSelector:@selector(countAll)];
[string performSelector:@selector(pushViewController)];
[string performSelector:@selector(test)];
NSLog(@"finish test");
}
@interface ZMCountButton : UIButton
@property (nonatomic, assign) NSInteger count;
@end
@interface ZMClickCount : NSObject
+ (instancetype)sharedInstance;
- (NSInteger)clickCount;
@end
#import <objc/runtime.h>
@implementation ZMCountButton
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method oriMethod = class_getInstanceMethod(self.class, @selector(sendAction:to:forEvent:));
Method cusMethod = class_getInstanceMethod(self.class, @selector(customSendAction:to:forEvent:));
// 判断自定义的方法是否实现, 避免崩溃
BOOL addSuccess = class_addMethod(self.class, @selector(sendAction:to:forEvent:), method_getImplementation(cusMethod), method_getTypeEncoding(cusMethod));
if (addSuccess) {
// 没有实现, 将源方法的实现替换到交换方法的实现
class_replaceMethod(self.class, @selector(customSendAction:to:forEvent:), method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
} else {
// 已经实现, 直接交换方法
method_exchangeImplementations(oriMethod, cusMethod);
}
});
}
- (void)customSendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
_count = [[ZMClickCount sharedInstance] clickCount];
[self customSendAction:action to:target forEvent:event];
}
@end
@interface ZMClickCount()
@property (nonatomic, assign) NSInteger count;
@end
@implementation ZMClickCount
+ (instancetype)sharedInstance {
static ZMClickCount *_instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
});
return _instance;
}
- (NSInteger)clickCount {
++_count;
NSLog(@"点击了 %ld次", _count);
return _count;
}
@end
- (void)countButtonClick:(UIButton *)sender {
self.testLabelText = [NSString stringWithFormat:@"点击 %ld 次了", self.testButton.count];
}
#pragma mark - 懒加载
- (ZMCountButton *)testButton {
if (!_testButton) {
_testButton = [ZMCountButton buttonWithType:UIButtonTypeCustom];
[_testButton addTarget:self action:@selector(countButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[_testButton setTitle:@"统计此按钮的点击数量" forState:UIControlStateNormal];
_testButton.frame = CGRectMake(20, self.view.center.y + 100, [UIScreen mainScreen].bounds.size.width - 40, 30);
_testButton.backgroundColor = [UIColor redColor];
}
return _testButton;
}
#import <Foundation/Foundation.h>
@protocol ModelDelegate <NSObject>
@optional
// 用在三级数组转换
+ (NSDictionary *)arrayContainModelClass;
@end
@interface NSObject (NNKeyValues)
/** 字典转模型 **/
+ (instancetype)modelWithDict:(NSDictionary *)dict;
@end
#import "NSObject+ZMKeyValues.h"
#import <objc/runtime.h>
@implementation NSObject (ZMKeyValues)
/** 字典转模型 **/
+ (instancetype)modelWithDict:(NSDictionary *)dict {
id objc = [[self alloc] init];
unsigned int count = 0;
// 获取成员属性数组
Ivar *ivarList = class_copyIvarList(self, &count);
// 遍历所有的成员属性名
for (int i = 0; i < count; i ++) {
// 获取成员属性
Ivar ivar = ivarList[i];
// 获取成员属性名
NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivar)];
NSString *key = [ivarName substringFromIndex:1];
// 从字典中取出对应 value 给模型属性赋值
id value = dict[key];
// 获取成员属性类型
NSString *ivarType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
// 判断 value 是不是字典
if ([value isKindOfClass:[NSDictionary class]]) {
ivarType = [ivarType stringByReplacingOccurrencesOfString:@"@" withString:@""];
ivarType = [ivarType stringByReplacingOccurrencesOfString:@"\"" withString:@""];
Class modalClass = NSClassFromString(ivarType);
// 字典转模型
if (modalClass) {
// 字典转模型
value = [modalClass modelWithDict:value];
}
}
if ([value isKindOfClass:[NSArray class]]) {
// 判断对应类有没有实现字典数组转模型数组的协议
if ([self respondsToSelector:@selector(arrayContainModelClass)]) {
// 转换成id类型,就能调用任何对象的方法
id idSelf = self;
// 获取数组中字典对应的模型
NSString *type = [idSelf arrayContainModelClass][key];
// 生成模型
Class classModel = NSClassFromString(type);
NSMutableArray *arrM = [NSMutableArray array];
// 遍历字典数组,生成模型数组
for (NSDictionary *dict in value) {
// 字典转模型
id model = [classModel modelWithDict:dict];
[arrM addObject:model];
}
// 把模型数组赋值给value
value = arrM;
}
}
// KVC 字典转模型
if (value) {
[objc setValue:value forKey:key];
}
}
return objc;
}
@end
- (void)initView {
[super initView];
NSDictionary *person = @{@"name":@"Chen",
@"sex": @"男"};
NSDictionary *dict = @{@"coderID":@"99",
@"nickName": @"rattanchen",
@"phoneNumber": @"138****8888",
@"person" : person};
NSArray *addarr = @[dict ,dict, dict];
NSMutableDictionary *mudict = [NSMutableDictionary dictionaryWithDictionary:dict];
[mudict setObject:person forKey:@"person"];
for (NSDictionary *item in addarr) {
ZMCoding *coding = [ZMCoding modelWithDict:item];
[self.dataArray addObject:coding];
}
if (self.dataArray.count) {
self.testLabelText = @"字典转模型成功, 点击查看对应的值";
}
}
- (void)buttonClick:(UIButton *)sender {
ZMCoding *coding = self.dataArray.firstObject;
switch (sender.tag) {
case 0:
self.testLabelText = coding.coderID;
break;
case 1:
self.testLabelText = coding.nickName;
break;
case 2:
self.testLabelText = coding.phoneNumber;
break;
case 3:
self.testLabelText = coding.person.name;
break;
case 4:
self.testLabelText = coding.person.sex;
break;
default:
break;
}
}
- (NSArray *)buttonTitleArray {
return @[@"ID", @"昵称", @"手机号", @"姓名", @"性别"];
}
- (NSMutableArray *)dataArray {
if (!_dataArray) {
_dataArray = [NSMutableArray array];
}
return _dataArray;
}
@end
#import <Foundation/Foundation.h>
#import "NSObject+ZMKeyValues.h"
#import "ZMPerson.h"
@interface ZMCoding : NSObject<NSCoding>
@property (nonatomic, strong) ZMPerson *person;
@property (nonatomic, copy) NSString *coderID;
@property (nonatomic, copy) NSString *nickName;
@property (nonatomic, copy) NSString *phoneNumber;
@end
#import <objc/runtime.h>
@implementation ZMCoding
- (void)encodeWithCoder:(NSCoder *)aCoder {
unsigned int count = 0;
// 获取类中所有属性
Ivar *ivars = class_copyIvarList(self.class, &count);
// 遍历属性
for (int i = 0; i < count; i ++) {
// 取出 i 位置对应的属性
Ivar ivar = ivars[i];
// 查看属性
const char *name = ivar_getName(ivar);
NSString *key = [NSString stringWithUTF8String:name];
// 利用 KVC 进行取值,根据属性名称获取对应的值
id value = [self valueForKey:key];
[aCoder encodeObject:value forKey:key];
}
free(ivars);
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
if (self = [super init]) {
unsigned int count = 0;
// 获取类中所有属性
Ivar *ivars = class_copyIvarList(self.class, &count);
// 遍历属性
for (int i = 0; i < count; i ++) {
// 取出 i 位置对应的属性
Ivar ivar = ivars[i];
// 查看属性
const char *name = ivar_getName(ivar);
NSString *key = [NSString stringWithUTF8String:name];
// 进行解档取值
id value = [aDecoder decodeObjectForKey:key];
// 利用 KVC 对属性赋值
[self setValue:value forKey:key];
}
}
return self;
}
@end
- (void)initView {
[super initView];
ZMCoding *coding = [ZMCoding new];
coding.coderID = @"99";
coding.nickName = @"rattanchen";
coding.phoneNumber = @"138****8888";
NSString *path = [ZMTools getDomainsPathWithFile:@"123"];
BOOL isSuc = [NSKeyedArchiver archiveRootObject:coding toFile:path];
if (isSuc == YES) {
self.testLabelText = @"归档成功, 点击按钮取出模型中对应的值";
}else{
self.testLabelText = @"归档失败";
}
}
- (void)buttonClick:(UIButton *)sender {
NSString *path = [ZMTools getDomainsPathWithFile:@"123"];
ZMCoding *coding = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
coding.coderID = @"999";
if (sender.tag == 0) {
self.testLabelText = coding.coderID;
} else if (sender.tag == 1) {
self.testLabelText = coding.nickName;
} else {
self.testLabelText = coding.phoneNumber;
}
}
- (NSArray *)buttonTitleArray {
return @[@"ID", @"昵称", @"手机号"];
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。