iOS高級面試題(一)內存管理篇--runtime(一)

runtime:運行時機制

  1. 是什麼?

 -  1.1 runtime是一套比較底層的純C語言的API,runtime就是一個庫,一個C語言庫,包含了許多底層的C語言API

  -  1.2平時我們編寫的OC代碼,在程序運行過程中,其實最終都是轉成了runtime的C語言代碼,runtime算是OC的幕後工作者,是整個OC的底層

   - 1.3舉個例子
  oc中的代碼:[Student alloc] init]經過runtime後,其實最終在底層生成C語言代碼:
  objc_msgSend(objc_msgSend("Student","alloc"), "init")
  objc_msgSend其實就是想某個對象發送什麼消息,這個函數第一個參數是類型或對象名,第二個參數是消息的名字,這些代碼比較底層

  2. 用過嗎?怎麼用?
   - 2.1 runtime是屬於OC的底層,可以進行一些非常底層的操作(用OC無法實現的,或者說不好實現)eg
   - *在程序運行過程中,動態創建一個類,(比如KVO和KVC的底層實現)
   - *在程序運行過程中,動態爲某個類添加屬性/方法,修改屬性值,修改方法
   - *遍歷一個類中所有的屬性和實例變量和所有方法

  3. 
  -  3.1相關的頭文件
  - #import //消息發送機制,可以直接用底層函數,進行消息發送
  -  3.2相關應用
  - *NSCoding(歸檔和解擋)
  -  *字典轉模型(利用runtime遍歷模型對象的所有屬性,根據屬性名從字典中取出對應的值,設置到模型的屬性上)
  - *kvo(利用runtime動態產生一個類)

   - 3.3相關函數
  msg_send:給對象發送消息,來自
  class_copyMethodList,遍歷某個類中所有的方法,來自
  class_copyIvarList,遍歷某個類中所有的實例變量的方法,來自

  運行時必備常識:
  1.Ivar:成員變量的意思
  2.Method:成員方法的意思
  3.property:屬性
  1. 你使用過Objective-C的運行時編程(Runtime Programming)麼?如果使用過,你用它做了什麼?你還能記得你所使用的相關的頭文件或者某些方法的名稱嗎?

runtime 運行時的動態添加屬性方法,
動態添加 set 方法

OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)

動態添加 get 方法

OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_1);

具體方法使用如下

#import <UIKit/UIKit.h>

@interface UIControl (ReName)

@property (nonatomic, copy) NSString *reName;

@end

UIControl+ReName.m

#import "UIControl+ReName.h"
#import <objc/runtime.h>
static const char * RENAME_CONST = "RECONST";

@implementation UIControl (ReName)

-(void)setReName:(NSString *)reName
{
    objc_setAssociatedObject(self, RENAME_CONST, reName, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

-(NSString *)reName
{
   return objc_getAssociatedObject(self, RENAME_CONST);
}
@end

使用方法如下

- (void)viewDidLoad {
    [super viewDidLoad];
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    button.reName = @"my name is new button";
    NSLog(@"%@",button.reName);
}

常用的方法使用名稱

// 1.獲得類中的所有成員變量

Ivar*ivarList =class_copyIvarList([selfclass], &count);

//2.獲得方法的名字的字符串

NSSelectorFromString(_cmd)

//3.發送消息函數

objc_msgSend()

runtim 運行時 動態歸檔方法代碼如下
調用方法

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    Student *student = [[Student alloc] init];
    student.name1 = @"sunlin";
    student.age = 18;
    student.name2 = @"sunlin";
    student.name3 = @"sunlin";
    student.name4 = @"sunlin";
    student.name5 = @"sunlin";
    student.name6 = @"sunlin";
    student.name7 = @"sunlin";
    //  歸檔文件的路徑
    NSString *filePath = [NSHomeDirectory()stringByAppendingPathComponent:@"person.archiver"];
    //  判斷該文件是否存在
    if (![[NSFileManager defaultManager]fileExistsAtPath:filePath]) {
        //  不存在的時候,歸檔存儲一個Student的對象
        NSMutableData *data = [NSMutableData data];
        NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:data];
        [archiver encodeObject:student forKey:@"student"];
        [archiver finishEncoding];

        BOOL success = [data writeToFile:filePath atomically:YES];
        if (success) {
            NSLog(@"歸檔成功!");
        }
    } else{
        //  存在的時候,不再進行歸檔,而是解擋!
        NSData *data = [NSData dataWithContentsOfFile:filePath];
        NSKeyedUnarchiver *unArchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
        Student *studentFromSaving = [unArchiver decodeObjectForKey:@"student"];

        NSLog(@"%@, %lu", studentFromSaving.name7, studentFromSaving.age);
    }

    return YES;

}

Student.h

#import <Foundation/Foundation.h>

@interface Student : NSObject<NSCoding>
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, copy) NSString *name1;
@property (nonatomic, copy) NSString *name2;
@property (nonatomic, copy) NSString *name3;
@property (nonatomic, copy) NSString *name4;
@property (nonatomic, copy) NSString *name5;
@property (nonatomic, copy) NSString *name6;
@property (nonatomic, copy) NSString *name7;


@end

Student.m

#import "Student.h"
#import <objc/runtime.h>

@implementation Student

-(void)encodeWithCoder:(NSCoder *)aCoder
{
    unsigned int count = 0;
    Ivar *ivars = class_copyIvarList([self class], &count);
    for (int i = 0; i < count; i++) {
        Ivar ivar = ivars[i];
        const char *name =ivar_getName(ivar);
        NSString *nameStr = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
        id value = [self valueForKey:nameStr];
        [aCoder encodeObject:value forKey:nameStr];
    }
    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++) {
            Ivar ivar = ivars[i];
            const char *name = ivar_getName(ivar);
            NSString *key = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
            id value = [aDecoder decodeObjectForKey:key];
            [self setValue:value forKey:key];
        }
        free(ivars);
    }
    return self;
}
@end
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章