How is dictionary[#"key"] implemented in objective c? - objective-c

If we want to override [dictionary objectForKey:#"key"] it can be done by subclassing NSDictionary class. How to override dictionary[#"key"]? In this context I want to know how dictionary[#"key"] is implemented.
Thanks!
Edit:
I wanted to find a scalable way to parse an API response while preventing [NSNull null] from crashing my app. I have written category for NSDictionary, but I wanted a way to parse in this syntax: data[#"key"]
So, I was evaluating the feasibility of subclassing NSDictionary.

When you use dictionary[#"key"] this gets converted into a call to [dictionary objectForKeyedSubscript:#"key"]. objectForKeyedSubscript: has the same behaviour as objectForKey:.
If you want to change the behaviour of dictionary[#"key"] then you will need to override objectForKeyedSubscript:.
Apple's NSDictionary API Reference has a little more information.

EDIT: This question is pretty old now, but it just recently came to my attention again, so I thought I would add an example of wrapping NSDictionary as I would recommend. This could be made more robust and feature rich, but it's an okay place to start.
#interface NilSafeDictionary: NSObject
-(instancetype)initWithDictionary:(NSDictionary*)dictionary;
#end
/** Category on NSDictionary to create a nil-safe wrapper. */
#interface NSDictionary <NilSafeConvenience>
- (NilSafeDictionary*)nilSafe;
#end
#implementation NilSafeDictionary {
NSDictionary* _internalDict;
}
- (instancetype)initWithDictionary:(NSDictionary*)dictionary {
self = [super init];
if (self) {
_internalDict = [dict copy];
}
return self;
}
- (id)objectForKeyedSubscript:(id<NSCopying>)key {
id obj = _internalDict[key];
if ([obj isKindOfClass:[NSNull class]]) {
return nil;
}
return obj;
}
#end
#implementation NSDictionary <NilSafeConvenience>
- (NilSafeDictionary*)nilSafe {
return [[NilSafeDictionary alloc] initWithDictionary:self];
}
#end
CAVEAT: You don't explain here what problem you're trying to solve, but for anyone who comes across this question in the future, subclassing NSDictionary is almost certainly never what you want.
NSDictionary is a class cluster. Class clusters are tricky to subclass correctly with guidance, plus Apple's documentation explicitly tells you not to subclass, so there's no guidance on how to do it correctly.
Even if you're able to use your subclass and have it "work correctly" for your purposes, every other piece of code in the system will still be returning the original NSDictionary class, not your subclass, so it doesn't benefit you.
If you're hell bent on modifying the way NSDictionary works, create your own wrapper class that has an NSDictionary inside and create your own objectForKeyedSubscript: implementation.
Yes, you can add subscript indexing to your own custom class just like NSDictionary!

dictionary[#key] is short hand for calling [dictionary objectForKeyedSubscript:#"key"]. Therefore to override the functionality of dictionary[#"key"] you can subclass NSDictionary.
#interface MyDictionary : NSDictionary
- (id) objectForKeyedSubscript:(id)key;
#end
#implementation MyDictionary
- (id) objectForKeyedSubscript:(id)key
{
/*
...
*/
}
#end
Original answer using categories, however this approach isn't advised as it will override the original method removing access to super and potential of clashes should multiple categories be loaded overriding the same method. The last category to be loaded will be used at runtime, therefore you cannot guarantee which that will be.
dictionary[#key] is short hand for calling [dictionary objectForKeyedSubscript:#"key"]. Therefore to override the functionality of dictionary[#"key"] you would create a new category for NSDictionary.
//Category in NSDictionary+CustomKeyedSubscript.h and NSDictionary+CustomKeyedSubscript.m
#interface NSDictionary (CustomKeyedSubscript)
- (id) objectForKeyedSubscript:(id)key;
#end
#implementation NSDictionary (CustomKeyedSubscript)
- (id) objectForKeyedSubscript:(id)key
{
/*
...
*/
}
#end

Related

Know when an object is created

Is there any way to use the ObjC runtime library, or Cocoa, to be notified when an object is created, for example, after it returns from the init method?
I want to achieve this without modifying the object, or subclassing it (no subclass on NSObject, for example) and without method swizzling (I already know how to do that).
There is no sanctioned way to be notified when a method executes, unless it specifically notes that it returns a notification, or a pointer to some kind of callback, a block, etc. While swizzling may be one way of going about it, proxying is probably your best bet. Instead of messing with the selector for an entire class, you interpose yourself "as" the class by implementing all its properties and/or forwarding selectors to the target object. In this way, NSProxy and subclasses can be used as wrappers around normal objects, meaning you can respond to any kind of method that happens to be sent through your proxy before forwarding it on to the target. A simple proxy can be modeled after the sample below:
FOUNDATION_EXPORT NSString *const CFIProxyDidInitializeTargetNotification;
#interface CFIObjectProxy : NSProxy {
__strong Foo *_target;
}
- (id)init;
#property(nonatomic, readonly, retain) NSArray* bars;
#end
//...
#import "CFIObjectProxy.h"
NSString *const CFIProxyDidInitializeTargetNotification = #"CFIProxyDidInitializeTargetNotification";
#implementation CFIObjectProxy
- (id)init {
_target = [[Foo alloc]init];
[NSNotificationCenter.defaultCenter postNotificationName:CFIProxyDidInitializeTargetNotification object:nil];
return self;
}
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation invokeWithTarget:_target];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
return [_target methodSignatureForSelector:sel];
}
- (NSString *)description {
return [_target description];
}
- (NSString *)debugDescription {
return [NSString stringWithFormat:#"<%#:%p> Proxy for Object: %#", NSStringFromClass(self.class), self, _target];
}
- (NSArray*)bars {
return [_target bars];
}
#end
Per default, the runtime doesn't record this. I think I'd use swizzling BUT as you don't want this... I think that CodaFi's idea of wrapping the object in a proxy is best ALTHOUGH this is only an option for allocations you manually do AFAICS
so if you want it to be truly transparent, swizzle after all I'd say

Does Objective-C have an equivalent to java annotations?

Does Objective-C have an equivalent to java annotations?
What's I'm trying to do is create a property and be able to somehow access some metadata about it.
I want to be able to determine what type of classes should go in my array so I'd like to annotate it somehow to say so. Then later be able to access that annotation via something like the runtime library where I can access lists of properties and their names.
//Put some sort of annotation giving a class name.
#property (strong) NSArray *myArray;
You said:
I want to be able to determine what type of classes should go in my array so I'd like to annotate it somehow to say so. Then later be able to access that annotation via something like the runtime library where I can access lists of properties and their names.
There are a few ways to do this sort of thing in Objective-C. Apple's frameworks do this sort of thing by adding a class method that returns the required information. Examples: dependent keys in KVO, +[CALayer needsDisplayForKey:] and related methods.
So, let's create a class method that returns an array of classes that can go into your container property, given the property name. First, we'll add a category to NSObject to implement a generic version of the method:
#interface NSObject (allowedClassesForContainerProperty)
+ (NSArray *)allowedClassesForContainerPropertyWithName:(NSString *)name;
#end
#implementation NSObject (allowedClassesForContainerProperty)
+ (NSArray *)allowedClassesForContainerPropertyWithName:(NSString *)name {
if (class_getProperty(self, name.UTF8String)) {
return #[ [NSObject class] ];
} else {
[NSException raise:NSInvalidArgumentException
format:#"%s called for non-existent property %#", __func__, name];
abort();
}
}
#end
As you can see, this default version of the method doesn't do anything particularly useful. But adding it to NSObject means we can send the message to any class without worrying about whether that class implements the method.
To make the message return something useful, we override it in our own classes. For example:
#implementation MyViewController
+ (NSArray *)allowedClassesForContainerPropertyWithName:(NSString *)name {
if ([name isEqualToString:#"myArray"]) {
return #[ [UIButton class], [UIImageView class] ];
} else {
return [super allowedClassesForContainerPropertyWithName:name];
}
}
...
We can use it like this:
SomeViewController *vc = ...;
SomeObject *object = ...;
if ([[vc.class allowedClassesForContainerPropertyWithName:#"bucket"] containsObject:object.class]) {
[vc.bucket addObject:object];
} else {
// oops, not supposed to put object in vc.bucket
}
There is no native support of this functionality, but you may to take a look at following solution — https://github.com/epam/lib-obj-c-attr/ It is compile time implementation of attributes. Definition of attributes based on defines but not on comments as in other solutions like ObjectiveCAnnotate.
Objective C does not support generics like in Java but ofcourse the language is very flexible that you can accomplish almost anything with simple tricks and knowledge. To implement a generic like feature you could create a category on NSArray class and create your own method to initialize the array and then check to see if the object is really the type of the object you want.
I would write a simple category on NSArray to have such functionality. Say suppose, I want my array to hold objects of class MyClass only then my category would look like,
#interface NSArray(MyCategory)
#end
#implementation NSArray(MyCategory)
-(NSArray*)arrayWithMyClasses:(NSArray*)classes{
if([classes count] > 0){
NSMutableArray *array = [[NSMutableArray alloc] init];
for(id anObj in classes){
NSAssert([anObj isKindOfClass:[MyClass class]], #"My array supports only objetcts of type MyClass");
[array addObject:anObj];
}
return array;
}
return nil;
}
#end
Of course, there is some limitations to it. Since you have created your own category, you should use your own method to initialize and create your own array.
No, Objective-C has no annotation or generics support.
A way to implement such a thing would be to hack Clang to read comments and associate a metadata object to the original object. But, you would be tied to your hacked compiler.
NSString *v1 = [[NSString alloc] init];
// associate
static char key;
NSString *v2 = [[NSString alloc] init];
objc_setAssociatedObject (
v1,
&key,
v2,
OBJC_ASSOCIATION_RETAIN
);
// retrieve
NSString *associate = (NSString *)objc_getAssociatedObject(v1, &key);
Qualifying with a protocol wouldn't be much trouble, and you could test if the collection implements it, but along the way you would need to create a category for each type on the same collection. This would require a different collection at compile time using macros. Overly complicated.
#interface Tomato:NSObject #end
#implementation Tomato #end
#protocol TomatoNSArray <NSObject>
- (Tomato*)objectAtIndexedSubscript:(NSUInteger)index;
- (void)setObject:(Tomato*)tomato atIndexedSubscript:(NSUInteger)index;
#end
// here is the problem, you would need to create one of this for each type
#interface NSMutableArray (TomatoNSArray) <TomatoNSArray>
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
NSMutableArray<TomatoNSArray> *tomatoes = [[NSMutableArray alloc] initWithCapacity:2];
tomatoes[0] = [Tomato new];
tomatoes[1] = [NSObject new]; // warning: incompatible pointer types
}
}
Does Objective-C have an equivalent to java annotations?
Not exactly an equivalent, but there is, and it's better. In Objective-C, the compiler has to store some type and name information in the compiled code (because the language is highly dynamic, a lot of things happen at runtime as opposed to compile time), for example method names ("selectors"), method type signatures, data about properties, protocols, etc. The Objective-C runtime library then has access to this data. For example, you can get the list of properties an object has by writing
id object = // obtain an object somehow
unsigned count;
objc_property_t *props = class_copyPropertyList([object class], &count);
Or you can check what class an object belongs to:
if ([object isKindOfClass:[NSArray class]]) {
// do stuff
}
(Yes, part of the runtime library is itself wrapped into some methods of NSObject for convenience, others only have C function APIs.)
If you specifically want to store custom metadata about an object or a class, you can do that using associated references.
I expect it should be clear now, the answer is NO, not at the moment.
Some people found some alternatives which seem to work in their specific use cases.
But in general there is no comparable feature yet in objective-c. IMHO clang metadata seems to provide a good foundations for this, but as long as there is not support from Apple this will not help, as far as i understood it.
Btw. I guess it should be clear, but just to repeat for all: two changes are required to support annotations as provided in java.
The language need an extension the annotate e.g. methodes, properites, classes, ... in the source code.
A standard interface is required to access the annotated information. This can only provide by apple.
Most alternativ soltuions move the annotation information into runtime and define their own interface. The objective-c runtime provide a standard interface but only with some trick you can annotate properties and still the isse of runtime population.
The typical use case for suche a feature is an IOC container (in Java e.g. Spring) which use the annotated information to inject other objects.
I would suggest to open an feature requrest for Apple to support this.
The answer to your question is that Objective-C does not have a direct equivalent of annotations as found in Java/C#, and though as some have suggested you might be able to engineer something along the same lines it probably is either far too much work or won't pass muster.
To address your particular need see this answer which shows how to construct an array which holds objects of only one type; enforcement is dynamic and not static as with parametric types/generics, but that is what you'd be getting with your annotation so it probably matches your particular need in this case. HTH.
What you need maybe a metadata parser for Objective-C. I have used ObjectiveCAnnotate (compile time retrievable) and ROAnnotation(runtime retrievable).

Objective-c categories

I'm learning Objective-C and now I'm stuck with categories. Here is the code
#import <Foundation/Foundation.h>
#interface NSMutableArray (NSMutableArrayCategory)
-(NSMutableArray *)removeLastObject;
#end
#import "NSMutableArrayCategory.h"
#implementation NSMutableArray (NSMutableArrayCategory)
-(NSMutableArray *)removeLastObject
{
return [self removeObjectAtIndex:[self count] - 1];
}
#end
The problem is that I get
Returning void from a function with incompatible result type 'NSMutableArray' *
What is wrong here ?
You probably want to declare removeLastObject as returning void, not NSMutableArray.
#interface NSMutableArray (NSMutableArrayCategory)
- (void)removeLastObject;
#end
Then the implementation will look like this:
- (void)removeLastObject
{
[self removeObjectAtIndex:[self count] - 1];
}
This matches the other mutation methods on NSMutableArray.
The underlying problem is that removeLastObject is already defined and does what you want (so people don't recreate it). Some of the answers here are a little confusing, however, in that they suggest it's ok to use a category to override an existing method (or at least don't explicitly state that you must not do this). You must not do this. It is poorly defined behavior, and in some cases it is completely undefined behavior. You generally should subclass to override a method.
There is an advanced technique called swizzling that will allow you to do this without a subclass, but it is a very specialized and sometimes fragile technique, not for general use.
But in no case should you use a category to override an existing method.
Im not familiar with objective c. but i imagine that removeObjectAtIndex returns void. so I would try
[self removeObjectAtIndex:[self count] -1];
return self;
return self after removing item..

Instance Variables for Objective C Categories

I have a situation where it seems like I need to add instance variables to a category, but I know from Apple's docs that I can't do that. So I'm wondering what the best alternative or workaround is.
What I want to do is add a category that adds functionality to UIViewControllers. I would find it useful in all my different UIViewControllers, no matter what specific UIViewController subclass they extend, so I think a category is the best solution. To implement this functionality, I need several different methods, and I need to track data in between them, so that's what led me to wanting to create instance methods.
In case it's helpful, here's what I specifically want to do. I want to make it easier to track when the software keyboard hides and shows, so that I can resize content in my view. I've found that the only way to do it reliably is to put code in four different UIViewController methods, and track extra data in instance variables. So those methods and instance variables are what I'd like to put into a category, so I don't have to copy-paste them each time I need to handle the software keyboard. (If there's a simpler solution for this exact problem, that's fine too--but I would still like to know the answer to category instance variables for future reference!)
Yes you can do this, but since you're asking, I have to ask: Are you absolutely sure that you need to? (If you say "yes", then go back, figure out what you want to do, and see if there's a different way to do it)
However, if you really want to inject storage into a class you don't control, use an associative reference.
Recently, I needed to do this (add state to a Category). #Dave DeLong has the correct perspective on this. In researching the best approach, I found a great blog post by Tom Harrington. I like #JeremyP's idea of using #property declarations on the Category, but not his particular implementation (not a fan of the global singleton or holding global references). Associative References are the way to go.
Here's code to add (what appear to be) ivars to your Category. I've blogged about this in detail here.
In File.h, the caller only sees the clean, high-level abstraction:
#interface UIViewController (MyCategory)
#property (retain,nonatomic) NSUInteger someObject;
#end
In File.m, we can implement the #property (NOTE: These cannot be #synthesize'd):
#implementation UIViewController (MyCategory)
- (NSUInteger)someObject
{
return [MyCategoryIVars fetch:self].someObject;
}
- (void)setSomeObject:(NSUInteger)obj
{
[MyCategoryIVars fetch:self].someObject = obj;
}
We also need to declare and define the class MyCategoryIVars. For ease of understanding, I've explained this out of proper compilation order. The #interface needs to be placed before the Category #implementation.
#interface MyCategoryIVars : NSObject
#property (retain,nonatomic) NSUInteger someObject;
+ (MyCategoryIVars*)fetch:(id)targetInstance;
#end
#implementation MyCategoryIVars
#synthesize someObject;
+ (MyCategoryIVars*)fetch:(id)targetInstance
{
static void *compactFetchIVarKey = &compactFetchIVarKey;
MyCategoryIVars *ivars = objc_getAssociatedObject(targetInstance, &compactFetchIVarKey);
if (ivars == nil) {
ivars = [[MyCategoryIVars alloc] init];
objc_setAssociatedObject(targetInstance, &compactFetchIVarKey, ivars, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[ivars release];
}
return ivars;
}
- (id)init
{
self = [super init];
return self;
}
- (void)dealloc
{
self.someObject = nil;
[super dealloc];
}
#end
The above code declares and implements the class which holds our ivars (someObject). As we cannot really extend UIViewController, this will have to do.
I believe it is now possible to add synthesized properties to a category and the instance variables are automagically created, but I've never tried it so I'm not sure if it will work.
A more hacky solution:
Create a singleton NSDictionary which will have the UIViewController as the key (or rather its address wrapped as an NSValue) and the value of your property as its value.
Create getter and setter for the property that actually goes to the dictionary to get/set the property.
#interface UIViewController(MyProperty)
#property (nonatomic, retain) id myProperty;
#property (nonatomic, readonly, retain) NSMutableDcitionary* propertyDictionary;
#end
#implementation UIViewController(MyProperty)
-(NSMutableDictionary*) propertyDictionary
{
static NSMutableDictionary* theDictionary = nil;
if (theDictionary == nil)
{
theDictioanry = [[NSMutableDictionary alloc] init];
}
return theDictionary;
}
-(id) myProperty
{
NSValue* key = [NSValue valueWithPointer: self];
return [[self propertyDictionary] objectForKey: key];
}
-(void) setMyProperty: (id) newValue
{
NSValue* key = [NSValue valueWithPointer: self];
[[self propertyDictionary] setObject: newValue forKey: key];
}
#end
Two potential problems with the above approach:
there's no way to remove keys of view controllers that have been deallocated. As long as you are only tracking a handful, that shouldn't be a problem. Or you could add a method to delete a key from the dictionary once you know you are done with it.
I'm not 100% certain that the isEqual: method of NSValue compares content (i.e. the wrapped pointer) to determine equality or if it just compares self to see if the comparison object is the exact same NSValue. If the latter, you'll have to use NSNumber instead of NSValue for the keys (NSNumber numberWithUnsignedLong: will do the trick on both 32 bit and 64 bit platforms).
This is best achieved using the built-in ObjC feature Associated Objects (aka Associated References), in the example below just change to your category and replace associatedObject with your variable name.
NSObject+AssociatedObject.h
#interface NSObject (AssociatedObject)
#property (nonatomic, strong) id associatedObject;
#end
NSObject+AssociatedObject.m
#import <objc/runtime.h>
#implementation NSObject (AssociatedObject)
#dynamic associatedObject;
- (void)setAssociatedObject:(id)object {
objc_setAssociatedObject(self, #selector(associatedObject), object, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id)associatedObject {
return objc_getAssociatedObject(self, #selector(associatedObject));
}
See here for the full tutorial:
http://nshipster.com/associated-objects/
It mentioned in many document's online that you can't create create new variable in category but I found a very simple way to achieve that. Here is the way that let declare new variable in category.
In Your .h file
#interface UIButton (Default)
#property(nonatomic) UIColor *borderColor;
#end
In your .m file
#import <objc/runtime.h>
static char borderColorKey;
#implementation UIButton (Default)
- (UIColor *)borderColor
{
return objc_getAssociatedObject(self, &borderColorKey);
}
- (void)setBorderColor:(UIColor *)borderColor
{
objc_setAssociatedObject(self, &borderColorKey,
borderColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
self.layer.borderColor=borderColor.CGColor;
}
#end
That's it now you have the new variable.
Why not simply create a subclass of UIViewController, add the functionality to that, then use that class (or a subclass thereof) instead?
Depending on what you're doing, you may want to use Static Category Methods.
So, I assume you've got this kind of problem:
ScrollView has a couple of textedits in them. User types on text edit, you want to scroll the scroll view so the text edit is visible above the keyboard.
+ (void) staticScrollView: (ScrollView*)sv scrollsTo:(id)someView
{
// scroll view to someviews's position or some such.
}
returning from this wouldn't necessarily require the view to move back, and so it doesn't need to store anything.
But that's all I can thinkof without code examples, sorry.
I believe it is possible to add variables to a class using the Obj-C runtime.
I found this discussion also.

Binding to a relations property in Core Data

I'm new in Core Data, and i got a problem i can't get my head around how to do "the right way"
I'll try and examplify my problem.
I got a entity Car. And a list of all the cars in my program. The cars have some attributes, but they are not predefined. So for each car i want to be able to define some properties.
Therefore i have defined a new entity CarProperty, with a one to many relation with the car.
In the nscollectionview i would like to show some of the properties from the car, more specefic the number of kilometer (numKm) it has driven (if that property exist). So i want to bind it to a label. But how to do?
I can't say representedObject.properties.numKm, or representedObject.numKm.
How should I get around this?
Hope it makes sense.
This isn't an easy problem. The thing is, Core Data doesn't know anything about numKm as a property. How is it supposed to know that numKm corresponds to a particular CarProperty object?
The fundamental problem you're describing is key-value coding compliance. Cocoa's going to look for a method called numKm on the properties object. Not finding one, it'll try sending [properties valueForKey:#"numKm"]; Since valueForKey: doesn't know what to do with numKm, you get an error, but not before it calls [properties valueForUndefinedKey:#"numKm"]
But here's the catch: properties is an NSSet generated by Core Data, so you can't subclass it to override valueForUndefinedKey:. What you can do is create your own object that's KVC-compliant for your arbitrary properties and use that instead.
One solution is to subclass NSDictionary and make it act as a proxy. The primitive methods are count, objectForKey: and keyEnumerator. If you override these three methods, you can create an NSDictionary that's linked to your Car object and returns the appropriate CarProperty objects. For example:
#interface PropertyProxy : NSDictionary {
}
#property (nonatomic, readonly, assign) Car *car;
- (id)initWithCar:(Car *)car
#end
#implementation PropertyProxy
#synthesize car = _car;
- (id)initWithCar:(Car *)car {
if (!(self = [super init]))
return nil;
_car = car;
return self;
}
- (NSInteger)count {
return [car.properties count];
}
- (id)objectForKey:(NSString *)key {
return [[car.properties filteredSetUsingPredicate:[NSPredicate predicateWithFormt:#"key == %#", key]] anyObject];
}
- (NSEnumerator *)keyEnumerator {
return [[car valueForKeyPath:#"properties.key"] objectEnumerator];
}
#end
Then, in your Car class, do this:
#interface Car : NSManagedObject {
// other stuff
}
#property (nonatomic, readonly) NSDictionary *carProperties;
// other stuff
#end
#implementation Car
// other stuff
- (NSDictionary *)carProperties {
return [[[PropertyProxy alloc] initWithCar:self] autorelease];
}
#end
(Disclaimer: I just typed this into my web browser, so no guarantees this actually compiles :-))
As you can see, it's not the easiest thing in the world to do. You'll be able to set up key paths like this:
representedObject.carProperties.numKm;
Keep in mind that, while this is key-value coding compliant, it is not key-value observing compliant. So if numKm changes, you won't be able to observe that. You would need to do some extra work to make that happen.