I welcome dear habrazhiteli!<objc/runtime.h> on the contents of the header <objc/runtime.h> , but on some of the features of the language itself, which many developers don’t guess. Yes, you stumble upon them, reading the documentation, you note to yourself “hmm, I wonder, you have to dig a little”, but they usually quickly fly out of my head. And novice developers often even read the documentation diagonally.- (void)setSize:(CGFloat)x :(CGFloat)y , but this can be brought to the absolute: @interface TestObject : NSObject + (id):(int)value; - (void):(int)a; - (void):(int)a :(int)b; @end // ... TestObject *obj = [TestObject :2]; [obj :4]; [obj :5 :7]; @selector(:) and @selector(::) . - (id)objectAtIndexedSubscript:(NSUInteger)index; - (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)index; - (id)objectForKeyedSubscript:(id)key; - (void)setObject:(id)obj forKeyedSubscript:(id)key; id a = obj[1]; obj[@"key"] = a; @property@property ad in the header actually announces only the getter and mutator for some field. If you declare them directly, nothing will change: - (int)value; - (void)setValue:(int)newValue; obj.value = 2; int i = obj.value; NSArray *a = @[@1, @2, @3]; NSInteger c = a.count; @interface TestObject : NSObject - (void)setTitle:(NSString *)title; @end; //... TestObject *obj = [TestObject new]; obj.title = @"simple object"; @property ad looks much better, and for this it was introduced. Properties are best accessed through " . ", But conventional methods are best called via " [] ". Otherwise, the readability of the code starts to suffer.alloccalloc function, then specifying isa manually. In principle, this is just a replacement for alloc , and init can be sent later. // , void *newObject = calloc(1, class_getInstanceSize([TestObject class])); // isa Class *c = (Class *)newObject; c[0] = [TestObject class]; // __bridge_transfer- ARC - obj = (__bridge_transfer TestObject *)newObject; // init - ! obj = [obj init]; object_setClass((__bridge id)newObject, [TestObject class]); extern : extern void _objc_autoreleasePoolPrint(void); objc[26573]: ############## objc[26573]: AUTORELEASE POOLS for thread 0x7fff72fb0310 objc[26573]: 9 releases pending. objc[26573]: [0x100804000] ................ PAGE (hot) (cold) objc[26573]: [0x100804038] ################ POOL 0x100804038 objc[26573]: [0x100804040] 0x100204500 TestObject objc[26573]: [0x100804048] 0x100102fc0 __NSDictionaryM objc[26573]: [0x100804050] 0x1007000b0 __NSArrayI objc[26573]: [0x100804058] 0x1006000a0 __NSCFString objc[26573]: [0x100804060] 0x100600250 NSMethodSignature objc[26573]: [0x100804068] 0x100600290 NSInvocation objc[26573]: [0x100804070] 0x100600530 __NSCFString objc[26573]: [0x100804078] 0x100600650 __NSArrayI objc[26573]: ############## @property values@property only generates getter and mutator signatures. But if the property is synthesized (via @synthesize or by default), then ivar is also generated: @property NSMutableDictionary *dict; - (void)resetDict { _dict = nil; } @interface TestObject : NSObject { @public int field; } @implementation TestObject - (void)updateWithField:(int)field { self->field = field; } @end // ... TestObject *obj = [TestObject new]; obj->field = 200; instancetypeid type, which is essentially NSObject * , that is, the most basic type for objects that any other object can lead to. Convenient, but in some cases problems may arise. For example: [[MyClass sharedInstance] count]; sharedInstance returns an id , the code will be collected without warning even if there is no count method in MyClass . If sharedInstance returns an instancetype , then the Vorning will still appear, because the compiler clearly understands that an object is returned from the class of which sharedInstance is called.init/new/copy , etc.forwardingTargetForSelector: and forwardInvocation: - (id)forwardingTargetForSelector:(SEL)aSelector { if ([_dict respondsToSelector:aSelector]) { return _dict; } return [super forwardingTargetForSelector:aSelector]; } - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { NSMethodSignature *sig = [super methodSignatureForSelector:aSelector]; if ([NSStringFromSelector(aSelector) isEqualToString:@"allDamnKeys"]) { sig = [_dict methodSignatureForSelector:@selector(allKeys)]; } return sig; } - (void)forwardInvocation:(NSInvocation *)anInvocation { if ([NSStringFromSelector(anInvocation.selector) isEqualToString:@"allDamnKeys"]) { anInvocation.selector = @selector(allKeys); [anInvocation invokeWithTarget:_dict]; } } NSFastEnumerationfor..in cycles. They are supported by all default collections, but we can support as well. To do this, you need to support the NSFastEnumeration protocol, or rather, define the countByEnumeratingWithState:objects:count: method countByEnumeratingWithState:objects:count: but not everything is so simple! Here is the signature of this method: - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained [])buffer count:(NSUInteger)len len size) or select our own. A pointer to this buffer should be placed in the state->itemsPtr , and the number of objects in it should be returned from the function. Just do not forget that (in the documentation there is no) the field state->mutationsPtr should not be empty. If this is not done, then we get an unexpected SEGFAULT . But in the state->state field, you can write anything, but the best thing is to record the number of elements already sent. If there is nothing to give, you need to return zero. - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained [])buffer count:(NSUInteger)len { if (state->state >= _value) { return 0; } NSUInteger itemsToGive = MIN(len, _value - state->state); for (NSUInteger i = 0; i < itemsToGive; ++i) { buffer[i] = @(_values[i + state->state]); } state->itemsPtr = buffer; state->mutationsPtr = &state->extra[0]; state->state += itemsToGive; return itemsToGive; } for (NSNumber *n in obj) { NSLog(@"n = %@", n); } Source: https://habr.com/ru/post/210672/
All Articles