Date
Apr. 18th, 2024
 
2024年 3月 10日

Post: iOS: 用 Runtime 实现全局 NSCopying

iOS: 用 Runtime 实现全局 NSCopying

Published 12:11 Nov 20, 2014.

Created by @ezra. Categorized in #Programming, and tagged as #iOS.

Source format: Markdown

Table of Content

给每个类手动添加 NSCopying 支持真的很累, 干脆一次性解决吧:

#import <Foundation/Foundation.h>

@interface MXObject : NSObject <NSCopying>

@end
#import "MXObject.h"
#import <objc/runtime.h>

@implementation MXObject
- (instancetype)copyWithZone:(NSZone *)zone {
    id obj = [[[self class] allocWithZone:zone] init];

    unsigned int uVarCount = 0;
    Ivar *pVarList = class_copyIvarList(self.class, &uVarCount);

    for (unsigned int i = 0; i < uVarCount; ++i) {

        Ivar *pVar = pVarList+i;
        const char *typeEncoding = ivar_getTypeEncoding(*pVar);
        NSString *strTypeEncoding = [NSString stringWithUTF8String:typeEncoding];
//        const char *name = ivar_getName(*pVar);
//        NSLog(@"var name:%s, type:%s", name, typeEncoding);

        if ([strTypeEncoding hasPrefix:@"@"]) {

            // it is a object
            id o = object_getIvar(self, *pVar);
            o = [o copy];
            object_setIvar(obj, *pVar, o);

        } else {

            unsigned int size = 0;
            BOOL support = NO;
            size = [self sizeOfTypeEncoding:strTypeEncoding supported:&support];
            if (!support) {
                NSString *reason = [NSString stringWithFormat:@"Don't support type encoding %@", strTypeEncoding];
                NSException *exception = [NSException exceptionWithName:@"UnsupportedTypeException" reason:reason userInfo:nil];
                [exception raise];
            }
            ptrdiff_t offset = ivar_getOffset(*pVar);
            uint8_t *src = (uint8_t *)(__bridge void *)self + offset;
            uint8_t *dst = (uint8_t *)(__bridge void *)obj + offset;
            memcpy(dst, src, size);
        }
    }

    free(pVarList);

    return obj;
}

- (unsigned int)sizeOfTypeEncoding:(NSString *)typeEncoding supported:(BOOL *)support {
    *support = YES;
    unsigned int size = 0;
    if ([typeEncoding isEqualToString:@"c"] ||
        [typeEncoding isEqualToString:@"C"]) {
        size = sizeof(char);
    } else if ([typeEncoding isEqualToString:@"i"] ||
               [typeEncoding isEqualToString:@"I"]) {
        size = sizeof(int);
    } else if ([typeEncoding isEqualToString:@"s"] ||
               [typeEncoding isEqualToString:@"S"]) {
        size = sizeof(short);
    } else if ([typeEncoding isEqualToString:@"l"] ||
               [typeEncoding isEqualToString:@"L"]) {
        size = sizeof(long);
    } else if ([typeEncoding isEqualToString:@"q"] ||
               [typeEncoding isEqualToString:@"Q"]) {
        size = sizeof(long long);
    } else if ([typeEncoding isEqualToString:@"f"]) {
        size = sizeof(float);
    } else if ([typeEncoding isEqualToString:@"d"]) {
        size = sizeof(double);
    } else if ([typeEncoding isEqualToString:@"B"]) {
        size = sizeof(bool);
    } else {
        *support = NO;
        // v is void
        // * is char *
        // @ is object
        // # is class object
        // : is method selector
        // [ is array
        // { is struct
        // ( is union
        // b is bit
        // ^ pointer to type
        // ? other
        size = 0;
    }
    return size;
}
@end
Pinned Message
HOTODOGO
I'm looking for a SOFTWARE PROJECT DIRECTOR / SOFTWARE R&D DIRECTOR position in a fresh and dynamic company. I would like to gain the right experience and extend my skills while working in great teams and big projects.
Feel free to contact me.
For more information, please view online résumé or download PDF
本人正在寻求任职 软件项目经理 / 软件技术经理 岗位的机会, 希望加⼊某个新鲜⽽充满活⼒的公司。
如有意向请随时 与我联系
更多信息请 查阅在线简历下载 PDF