程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> Objective-C Runtime Classes

Objective-C Runtime Classes

編輯:關於C語言

Objective-C Runtime Classes


Objective-C語言的許多決策可以在編譯和運行時執行。只要有可能,它是動態的。這意味著Objective-C語言不僅需要一個編譯器,還需要一個運行時系統來執行編譯的代碼。Runtime系統是一種用於Objective-C語言的操作系統,它使OC語言工作起來。
  Runtime的核心是在運行時動態操作類和消息分發給其他對象,本文檔主要介紹在運行時動態操作類。
  你可以從中學到運行時動態操作類。但是,多數情況下,我們並不需要編寫Runtime系統的相關代碼。
  

注意:在Runtime中,所有的char * 數據是UTF-8編碼。


一、准備工作

1. 導入框架objc/runtime.h

#import < objc/runtime.h >

2. User類

User.h

//
//  User.h
//  Runtime
//
//  Created by yangjun on 15/9/21.
//  Copyright © 2015年 六月. All rights reserved.
//

#import 

/// 用戶
@interface User : NSObject

@property (nonatomic, copy) NSString *userName;///< 用戶名

/**
 *  初始化
 *
 *  @param userName 用戶名
 *
 *  @return id
 */
- (id)initWithUserName:(NSString *)userName;

/**
 *  初始化
 *
 *  @param userName 用戶名
 *
 *  @return id
 */
+ (id)userWithUserName:(NSString *)userName;

@end

User.m

//
//  User.m
//  Runtime
//
//  Created by yangjun on 15/9/21.
//  Copyright © 2015年 六月. All rights reserved.
//

#import User.h

@implementation User

+ (id)userWithUserName:(NSString *)userName
{
    User *user = [[User alloc] init];
    user.userName = userName;
    return userName;
}

#pragma mark 初始化
- (id)initWithUserName:(NSString *)userName
{
    self = [super init];
    if (self) {
        self.userName = userName;
    }
    return self;
}

@end

 

二、類

1.源代碼

#pragma mark - 類
- (void)testClass
{
    // 獲取類
    id userClass = objc_getClass(User);
    NSLog(@%@, userClass);
    // 等價
    userClass = [User class];
    NSLog(@%@, userClass);

    // 父類
    fprintf(stdout, 
父類
);
    id superUserClass = class_getSuperclass(userClass);
    NSLog(@%@, superUserClass);
    // 等價
    superUserClass = [User new].superclass;
    NSLog(@%@, superUserClass);

    // 更改對象的類
    fprintf(stdout, 
更改對象的類
);
    User *user = [User new];
    NSLog(@類:%@ userName:%@, user, user.userName);
    userClass = object_setClass(user, [ClassTest class]);// 類替換,並返回原來的類屬性
    NSLog(@類:%@ userName:%@, user, user.userName);
}


2.輸出
2015-09-23 10:12:52.140 Runtime[14129:681188] User
2015-09-23 10:12:52.141 Runtime[14129:681188] User

父類
2015-09-23 10:12:52.141 Runtime[14129:681188] NSObject
2015-09-23 10:12:52.141 Runtime[14129:681188] NSObject

更改對象的類
2015-09-23 10:12:52.141 Runtime[14129:681188] 類: userName:(null)
2015-09-23 10:12:52.141 Runtime[14129:681188] 類: userName:陽君

 

三、類名

1.源代碼

#pragma mark - 類名
- (void)testName{
    // 獲取class
    id userClass = objc_getClass(User);
    const char *className = class_getName(userClass);
    fprintf(stdout, 類名:%s
, className);
    // 等價
    className = object_getClassName(userClass);
    fprintf(stdout, 類名:%s
, className);
    // 等價OC
    userClass = [User class];
    NSString *name = NSStringFromClass(userClass);
    NSLog(@類名:%@, name);
    // 底層轉換
    name = [NSString stringWithCString:className encoding:NSUTF8StringEncoding];
    NSLog(@類名:%@, name);
}


2.輸出
類名:User
類名:User
2015-09-23 10:14:03.278 Runtime[14140:681770] 類名:User
2015-09-23 10:14:03.279 Runtime[14140:681770] 類名:User

 

四、屬性

1.源代碼

#pragma mark - 屬性
- (void)testPropertyName
{
    // 獲取所有屬性
    fprintf(stdout, 獲取所有屬性
);
    id userClass = objc_getClass(User);
    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList(userClass, &outCount);// 所有屬性
    for (i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];// 屬性
        const char *propertyName = property_getName(property);// 屬性名
        const char *propertyAttributes = property_getAttributes(property); //屬性類型
        fprintf(stdout, %s %s
, propertyName, propertyAttributes);
        // 等價輸出
        NSLog(@%@, [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]);
    }

    // 單一屬性
    fprintf(stdout, 
單一屬性
);
    Ivar var = class_getInstanceVariable(userClass, _userName);
    const char *typeEncoding =ivar_getTypeEncoding(var);
    const char *ivarName = ivar_getName(var);
    fprintf(stdout, 屬性名:%s; 類型:%s
, ivarName, typeEncoding);

    // 設置/獲取屬性值,需要關閉ARC模式
    fprintf(stdout, 
設置/獲取屬性值
);
    User *user = [[[User alloc] init] autorelease];
    NSString *userName = @陽君;
    object_setInstanceVariable(user, _userName, userName);
    NSLog(@user.userName:%@, user.userName);
    user.userName = @開啟ARC;// 修改值
    object_getInstanceVariable(user, _userName, (void*)&userName);
    NSLog(@user.userName:%@, userName);
}


2.輸出
獲取所有屬性
userName T@”NSString”,C,N,V_userName
2015-09-23 10:18:54.365 Runtime[14155:684097] userName

單一屬性
屬性名:_userName; 類型:@”NSString”

設置/獲取屬性值
2015-09-23 10:18:54.366 Runtime[14155:684097] user.userName:陽君
2015-09-23 10:18:54.367 Runtime[14155:684097] user.userName:開啟ARC

 

五、方法

1.源代碼
全局方法:

NSString *classAddMethodIMP(id self, SEL _cmd, NSString *str) {
    // implementation ....
    NSLog(@值:%@, str);
    return str;
}

NSString *userName(id self, SEL _cmd) {
    return @OC;
}

局部方法:

#pragma mark - 方法
- (void)testMethod
{
    // 獲取所有方法
    fprintf(stdout, 獲取所有方法
);
    id userClass = objc_getClass(User);
    u_int count;// unsigned int
    Method *methods= class_copyMethodList(userClass, &count);// 所有方法,只包含實例方法)
    for (int i = 0; i < count ; i++) {
        Method method = methods[i];
        SEL name = method_getName(method);// 轉為方法
        const char *selName = sel_getName(name);// 轉為方法名
        const char *methodTypeEncoding = method_getTypeEncoding(method);// 方法傳輸的參數
        char *methodType = method_copyReturnType(method);// 方法返回的類型
        fprintf(stdout, 方法名:%s; 返回類型%s; 參數:%s
, selName, methodType, methodTypeEncoding);
    }

    // 1.提取Method(類方法)
    fprintf(stdout, 
方法提取
);
    SEL name = sel_registerName(userWithUserName:);
    Method method = class_getClassMethod(userClass, name);
    name = method_getName(method);
    fprintf(stdout, 提取方法(+):%s
, sel_getName(name));
    // 2.提取Method(實例方法)
    name = sel_registerName(initWithUserName:);
    method = class_getInstanceMethod(userClass, name);
    name = method_getName(method);
    fprintf(stdout, 提取方法(-):%s
, sel_getName(name));
    // 3.提取IMP
    IMP imp = method_getImplementation(method);
    // 只能獲取(-)方法
    imp = class_getMethodImplementation(userClass, name);
    imp = class_getMethodImplementation_stret(userClass, name);
    // 等價
    User *user = [[User alloc] init];
    imp = [user methodForSelector:name];

    // 類增加方法(全局方法)
    fprintf(stdout, 
類增加方法
);
    name = sel_registerName(classAddMethodIMP);
    BOOL addMethod = class_addMethod(userClass, name, (IMP)classAddMethodIMP,i@:@);
    // 判斷類是否有此方法
    if (addMethod && class_respondsToSelector(userClass, name) && [user respondsToSelector:name]) {
        fprintf(stdout, 類%s添加方法%s成功
, class_getName(userClass), sel_getName(name));
    }
    // 類添加方法(-)
    name = @selector(classAddMethod:);
    method = class_getInstanceMethod(self.class, name);// 方法體
    imp = method_getImplementation(method);// 方法的實現
    class_addMethod(userClass, name, imp, v@:);
    // 方法調用
    id methodBack = [user performSelector:@selector(classAddMethod:) withObject:@陽君];
    NSLog(@類%@調用方法%@ 返回:%@, NSStringFromClass(user.class), [NSString stringWithCString:sel_getName(name) encoding:NSUTF8StringEncoding], methodBack);

    // 方法交換
    fprintf(stdout, 
方法交換
);
    Method m1 = class_getInstanceMethod([self class], @selector(userName));
    Method m2 = class_getInstanceMethod([self class], @selector(userName2));
    method_exchangeImplementations(m1, m2);
    NSLog(@%@, [self userName]);
    NSLog(@%@, [self userName2]);

    // 方法替換
    fprintf(stdout, 
方法替換
);
    Method userNameMethod = class_getInstanceMethod(self.class, @selector(userName));
    IMP userNameImp = method_getImplementation(userNameMethod);
    Method setUserNameMethod = class_getInstanceMethod(self.class, @selector(userName2));
    method_setImplementation(setUserNameMethod, userNameImp);
    NSLog(@%@, [self userName]);
    NSLog(@%@, [self userName2]);

    // 方法覆蓋,只能使用全局方法替換,方法名需要一致
    fprintf(stdout, 
方法覆蓋
);
    NSLog(@%@, user.userName);
    name = sel_registerName(userName);
    imp = class_replaceMethod(userClass, name, (IMP)userName,i@:@);
    NSLog(@%@, user.userName);
}

#pragma mark 覆蓋的方法
- (NSString *)userName
{
    return @陽君;
}

- (NSString *)userName2
{
    return @IOS;
}

#pragma mark 增加的方法
- (NSString *)classAddMethod:(NSString *)str
{
    return str;
}


2.輸出
獲取所有方法
方法名:initWithUserName:; 返回類型@; 參數:@24@0:8@16
方法名:userName; 返回類型@; 參數:@16@0:8
方法名:setUserName:; 返回類型v; 參數:v24@0:8@16

方法提取
提取方法(+):userWithUserName:
提取方法(-):initWithUserName:

類增加方法
類User添加方法classAddMethodIMP成功
2015-09-23 10:21:19.167 Runtime[14182:685354] 類User調用方法classAddMethod: 返回:陽君

方法交換
2015-09-23 10:21:19.168 Runtime[14182:685354] IOS
2015-09-23 10:21:19.168 Runtime[14182:685354] 陽君

方法替換
2015-09-23 10:21:19.168 Runtime[14182:685354] IOS
2015-09-23 10:21:19.168 Runtime[14182:685354] IOS

方法覆蓋
2015-09-23 10:21:19.169 Runtime[14182:685354] (null)
2015-09-23 10:21:19.169 Runtime[14182:685354] OC

 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved