Date
Oct. 18th, 2024
 
2024年 9月 16日

Post: iOS: 用 Runtime 实现全局 NSCopying

Today is the A Memorial Day

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
The Founder and CEO of Infeca Technology.
Developer, Designer, Blogger.
Big fan of Apple, Love of colour.
Feel free to contact me.
反曲点科技创始人和首席执行官。
开发、设计与写作皆为所长。
热爱苹果、钟情色彩。
随时恭候 垂询