Runtime的用法有哪几种

本文深入探讨Objective-C运行时的高级应用,包括动态类创建、属性和方法的获取与修改,以及方法交换等核心概念。通过实例展示了如何利用运行时API进行动态变量控制和方法添加,避免KVC赋值崩溃,实现方法动态交换。

1, 动态添加一个类, 就像KVO一样, 系统是在程序运行的时候根据你要监听的类, 动态添加一个新类继承自该类, 然后重写原类的setter方法并在里面通知observer的.

// 创建一个类(size_t extraBytes该参数通常指定为0, 该参数是分配给类和元类对象尾部的索引ivars的字节数。)
Class clazz = objc_allocateClassPair([NSObject class], "GoodPerson", 0);

// 添加ivar
// @encode(aType) : 返回该类型的C字符串
class_addIvar(clazz, "_name", sizeof(NSString *), log2(sizeof(NSString *)), @encode(NSString *));

class_addIvar(clazz, "_age", sizeof(NSUInteger), log2(sizeof(NSUInteger)), @encode(NSUInteger));

// 注册该类
objc_registerClassPair(clazz);

// 创建实例对象
id object = [[clazz alloc] init];

// 设置ivar
[object setValue:@"Tracy" forKey:@"name"];

Ivar ageIvar = class_getInstanceVariable(clazz, "_age");
object_setIvar(object, ageIvar, @18);

// 打印对象的类和内存地址
NSLog(@"%@", object);

// 打印对象的属性值
NSLog(@"name = %@, age = %@", [object valueForKey:@"name"], object_getIvar(object, ageIvar));

// 当类或者它的子类的实例还存在,则不能调用objc_disposeClassPair方法
object = nil;

// 销毁类
objc_disposeClassPair(clazz);
--------------------- 

2,

通过runtime获取一个类的所有属性

Person *p = [[Person alloc] init];
[p setValue:@"Kobe" forKey:@"name"];
[p setValue:@18 forKey:@"age"];
//    p.address = @"广州大学城";
p.weight = 110.0f;

// 1.打印所有ivars
unsigned int ivarCount = 0;
// 用一个字典装ivarName和value
NSMutableDictionary *ivarDict = [NSMutableDictionary dictionary];
Ivar *ivarList = class_copyIvarList([p class], &ivarCount);
for(int i = 0; i < ivarCount; i++){
    NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivarList[i])];
    id value = [p valueForKey:ivarName];

    if (value) {
        ivarDict[ivarName] = value;
    } else {
        ivarDict[ivarName] = @"值为nil";
    }
}
// 打印ivar
for (NSString *ivarName in ivarDict.allKeys) {
    NSLog(@"ivarName:%@, ivarValue:%@",ivarName, ivarDict[ivarName]);
}

// 2.打印所有properties
unsigned int propertyCount = 0;
// 用一个字典装propertyName和value
NSMutableDictionary *propertyDict = [NSMutableDictionary dictionary];
objc_property_t *propertyList = class_copyPropertyList([p class], &propertyCount);
for(int j = 0; j < propertyCount; j++){
    NSString *propertyName = [NSString stringWithUTF8String:property_getName(propertyList[j])];
    id value = [p valueForKey:propertyName];

    if (value) {
        propertyDict[propertyName] = value;
    } else {
        propertyDict[propertyName] = @"值为nil";
    }
}
// 打印property
for (NSString *propertyName in propertyDict.allKeys) {
    NSLog(@"propertyName:%@, propertyValue:%@",propertyName, propertyDict[propertyName]);
}

// 3.打印所有methods
unsigned int methodCount = 0;
// 用一个字典装methodName和arguments
NSMutableDictionary *methodDict = [NSMutableDictionary dictionary];
Method *methodList = class_copyMethodList([p class], &methodCount);
for(int k = 0; k < methodCount; k++){
    SEL methodSel = method_getName(methodList[k]);
    NSString *methodName = [NSString stringWithUTF8String:sel_getName(methodSel)];

    unsigned int argumentNums = method_getNumberOfArguments(methodList[k]);

    methodDict[methodName] = @(argumentNums - 2); // -2的原因是每个方法内部都有self 和 selector 两个参数
}
// 打印method
for (NSString *methodName in methodDict.allKeys) {
    NSLog(@"methodName:%@, argumentsCount:%@", methodName, methodDict[methodName]);
}
---------------------

3, 

动态变量控制,动态修改变量的值

-(void)changeAge{
     unsigned int count = 0;
     //动态获取XiaoMing类中的所有属性[当然包括私有] 
     Ivar *ivar = class_copyIvarList([self.xiaoMing class], &count);
     //遍历属性找到对应age字段 
     for (int i = 0; i<count; i++) {
         Ivar var = ivar[i];
         const char *varName = ivar_getName(var);
         NSString *name = [NSString stringWithUTF8String:varName];
         if ([name isEqualToString:@"_age"]) {
             //修改对应的字段值成20
             object_setIvar(self.xiaoMing, var, @"20");
             break;
         }
     }
     NSLog(@"XiaoMing's age is %@",self.xiaoMing.age);
 }

4, 

在NSObject的分类中增加方法来避免使用KVC赋值的时候出现崩溃

在有些时候我们需要通过KVC去修改某个类的私有变量,但是又不知道该属性是否存在,如果类中不存在该属性,那么通过KVC赋值就会crash,这时也可以通过运行时进行判断。同样我们在NSObject的分类中增加如下方法。

#import "NSObject+objc.h"
#import <objc/runtime.h>

@implementation NSObject (objc)

-(BOOL)hasProperty:(NSString *)property
{
    BOOL flag = NO;
    u_int count = 0;
    Ivar *ivars = class_copyIvarList([self class], &count);
    for (int i = 0; i < count; i++) {
        const char *propertyName = ivar_getName(ivars[i]);
        NSString *propertyString = [NSString stringWithUTF8String:propertyName];
        if ([propertyString isEqualToString:property]){
            flag = YES;
        }
    }
    return flag;
}

@end

5, 

利用runtime的动态交换方法实现

+(void)run
{
    NSLog(@"Person Run.....");
}

+(void)study
{
    NSLog(@"Person study.....");
}
// 获取两个类的类方法
    Method m1 = class_getClassMethod([Person class], @selector(run));
    Method m2 = class_getClassMethod([Person class], @selector(study));
    // 开始交换方法实现
    method_exchangeImplementations(m1, m2);
   [Person run];
    [Person study];

 

6,

动态添加方法

// void(*)()
// 默认方法都有两个隐式参数,
void eat(id self,SEL sel)
{
    NSLog(@"%@ %@",self,NSStringFromSelector(sel));
}

// 当一个对象调用未实现的方法,会调用这个方法处理,并且会把对应的方法列表传过来.
// 刚好可以用来判断,未实现的方法是不是我们想要动态添加的方法
+ (BOOL)resolveInstanceMethod:(SEL)sel
{

    if (sel == @selector(eat)) {
        // 动态添加eat方法

        // 第一个参数:给哪个类添加方法
        // 第二个参数:添加方法的方法编号
        // 第三个参数:添加方法的函数实现(函数地址)
        // 第四个参数:函数的类型,(返回值+参数类型) v:void @:对象->self :表示SEL->_cmd
        class_addMethod(self, @selector(eat), eat, "v@:");

    }

    return [super resolveInstanceMethod:sel];
}

 

转载于:https://www.cnblogs.com/dashengios/p/10596742.html

<think>嗯,用户想了解OpenFOAM中绘制网格的方法。首先,我需要回忆一下OpenFOAM的网格生成流程。根据之前的引用内容,OpenFOAM生成网格的步骤包括面、网格单元的分配,以及通过owner文件确定面的归属。然后,用户可能提到了两种方法:内部生成和外部导入。 内部生成的话,可能需要用blockMesh或snappyHexMesh。blockMesh是基础工具,通过定义块状结构来生成网格,适用于简单几何。snappyHexMesh更复杂,可以处理曲面和细化区域。这里得确认这两种工具的使用步骤和示例,比如blockMesh需要编写blockMeshDict文件,而snappyHexMesh需要先有基础网格。 然后是外部导入,比如从Fluent Meshing转换。引用2中提到,需要将.msh文件处理后再用fluent3DMeshToFoam转换。这里要注意删除多余的部分,否则会报错。转换后的网格存放在constant/polyMesh,还需要检查边界条件是否正确。用户可能需要具体的步骤,比如导出格式、文件处理命令等。 另外,代码示例部分,引用3中的createMesh.H文件展示了如何通过代码创建网格,这部分是求解器必须的,用户可能需要了解如何在代码中集成网格生成。需要解释IOobject和fvMesh的初始化过程。 可能用户的实际需求是选择适合他们项目的方法,比如简单几何用blockMesh,复杂几何用snappyHexMesh或者外部导入。还需要提醒检查边界条件和验证网格,比如用paraFoam查看。此外,常见问题比如转换失败可能因为.msh文件格式不正确,需要确保UTF8编码和处理多余内容。 相关问题部分,应该覆盖工具对比、转换问题、代码集成、优化方法等。比如,blockMesh和snappyHexMesh的区别,转换时报错如何处理,边界条件设置,网格优化方法等。这样用户能进一步探索具体问题。</think>### OpenFOAM中网格绘制方法分步说明 OpenFOAM的网格绘制主要分为**内部生成**和**外部导入**两种方式,具体方法如下: --- #### 一、内部网格生成方法 1. **blockMesh工具**(基础结构化网格) - 通过编写`blockMeshDict`文件定义几何块和拓扑结构 - 示例代码段: ```cpp // system/blockMeshDict vertices ( (0 0 0) // 顶点坐标定义 (1 0 0) (1 1 0) (0 1 0) // ...其他顶点 ); blocks ( hex (0 1 2 3 4 5 6 7) (20 20 1) simpleGrading (1 1 1) // 定义六面体块 ); ``` - 执行命令:`blockMesh` 生成网格[^3] 2. **snappyHexMesh工具**(复杂非结构网格) - 基于初始结构化网格进行曲面捕捉和局部细化 - 工作流程: - 先用blockMesh生成背景网格 - 通过STL表面几何定义细化区域 - 执行命令:`snappyHexMesh -overwrite` --- #### 二、外部网格导入方法 1. **从Fluent Meshing导入**(引用[2]具体流程) - 关键步骤: ```bash fluent3DMeshToFoam myMesh.msh # 转换命令 ``` - 必须预处理.msh文件:删除`TGrid variables`段落[^2] - 转换后需检查`constant/polyMesh/boundary`文件 2. **其他格式转换** - 支持Gmsh、STAR-CCM+等格式 - 使用工具:`gmshToFoam`, `ccm26ToFoam`等 --- #### 三、网格验证与后处理 1. 可视化检查 ```bash paraFoam # 启动可视化工具 ``` - 需勾选**Use VTK Polyhedron**显示多面体网格 2. 质量检查 ```bash checkMesh # 执行网格质量诊断 ``` --- #### 四、代码级网格控制(引用[3]) 在求解器中通过`createMesh.H`文件初始化网格: ```cpp Foam::fvMesh mesh ( Foam::IOobject ( Foam::fvMesh::defaultRegion, runTime.timeName(), runTime, Foam::IOobject::MUST_READ ) ); ``` 该代码段实现了从系统时间目录读取网格文件的功能。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值