Skip to content

Instantly share code, notes, and snippets.

@pookjw
Last active April 21, 2024 15:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pookjw/ee503a3396ccd106866cb6a9453e79ea to your computer and use it in GitHub Desktop.
Save pookjw/ee503a3396ccd106866cb6a9453e79ea to your computer and use it in GitHub Desktop.
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface MyObject : NSObject <NSCopying> {
@package NSUInteger _first;
@package NSInteger _second;
@package BOOL _third;
}
@end
@implementation MyObject
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
id copy = [[self class] new];
if (copy) {
unsigned int ivarsCount;
Ivar *ivars = class_copyIvarList([MyObject class], &ivarsCount);
ptrdiff_t minOffset = ivar_getOffset(ivars[0]);
ptrdiff_t maxOffset = ivar_getOffset(ivars[ivarsCount - 1]);
// https://github.com/opensource-apple/objc4/blob/cd5e62a5597ea7a31dccef089317abb3a661c154/runtime/objc-runtime-new.h#L236
uint32_t lastIvarSize = *(uint32_t *)((uintptr_t)ivars[ivarsCount - 1] + sizeof(int32_t *) + sizeof(const char *) + sizeof(const char *) + sizeof(uint32_t));
free(ivars);
const void *src = (const void *)((uintptr_t)self + minOffset);
void *dst = (void *)((uintptr_t)copy + minOffset);
memcpy(dst, src, maxOffset - minOffset + lastIvarSize);
}
return copy;
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
MyObject *myObject_1 = [MyObject new];
myObject_1->_first = 3;
myObject_1->_second = 2;
myObject_1->_third = YES;
MyObject *myObject_2 = [myObject_1 copy];
assert(myObject_1->_first == myObject_2->_first);
assert(myObject_1->_second == myObject_2->_second);
assert(myObject_1->_third == myObject_2->_third);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment