How to check what class was an object initialized in Objective C - iphone

Is it possible to check and get the name of the class an object was initialized in?
Example: I have Class A. I created object ABObject using [[ABOBject alloc] init]; via an instance method.
How can I find out the class from which an instance ABObject was created, namely "A" here?

Objects can be created outside the context of a class, so it wouldn't make sense for this to be a built-in language feature.
If you do have to do this, one way to work around it would be to use the objc_setAssociatedObjects() function in objc/runtime.h immediately after any such object was instantiated. Something like:
ABObject *object = [[ABObject alloc] init];
objc_setAssociatedObject(object, #"InstantiatingClassKey", [self class], OBJC_ASSOCIATION_ASSIGN);
Then you could get it with objc_getAssociatedObject(object, #"InstantiatingClassKey").
I think you'd be better off re-assessing your design because this is not going to be particularly maintainable. Even extracting this into a category on NSObject to remove duplicated code you'll still have an extra step to remember and weird relationships between your objects.
Also, as Martin R. points out in the comments, I'm taking a shortcut and passing a string literal as the key argument for the function, in reality you'd want to follow the practice of using the address of some static or global variable.

Related

CoreData Object typing won't work

Can someone explain to me why this doesn't work:
CoreDataClass *classObject = (CoreDataClass *)[some method that returns a dictionary with exact KVC pairs that match CoreDataClass];
NSString *myString = classObject.stringProperty;
But this does:
CoreDataClass *classObject = (CoreDataClass *)[some method that returns a dictionary with exact KVC pairs that match CoreDataClass];
NSString *myString = [classObject valueForKey:#"stringProperty"];
EDIT:
What's the easiest way to cast the dictionary as my NSManagedObjectClass CoreDataClass so I can access properties directly?
It doesn't work since KVC compliance is not at all what defines classes or makes them castable - the class hierarchy exists for a reason, and just ensuring adherence to certain methods doesn't magically make something an instance of a completely different class. Keep in mind that the dot-accessor syntax is just sugar for a method send, so these two are equivalent:
classObject.stringProperty
[classObject stringProperty]
...and the latter obviously isn't valid for instances of NSDictionary (i.e. [[NSDictionary class] instancesRespondToSelector:#selector(stringProperty)] is NO).
Your latter example works because of the very premise of your question: if something is KVC-compliant for the key stringProperty, and you ask it for a value for that key, then obviously you get something back. Furthermore, both NSDictionary and CoreDataClass respond to the selector -valueForKey:, so the message send actually works at runtime.
The best way to get the two across isn't a "cast" at all - it's a complete conversion, at the property level, of the data involved. You might consider creating a custom -initWith... method on CoreDataClass that lets you instantiate its properties from a dictionary, or finding a way to get your method to return an actual instance of CoreDataClass instead of an NSDictionary.
Note that this solution may differ from the "easiest" way to get the data across, which is effectively to keep doing what you're doing and use -valueForKey: (though preferably without the cast, which is misleading).
Casting objects only appears to work (in the sense that you won't get type-checking errors) because it's a hint to the compiler, but it doesn't actually change anything about what the pointer points to, so you are still pointing to an NSDictionary. This is because, at the end of the day, you are essentially casting a pointer to a pointer, but telling Xcode that you are allowed to send a different set of selectors to it.
For NSManagedObjects, creation from a dictionary depends on a few things, but the recommended way is to make a class method on your custom class which will use NSEntityDescription and you NSManagedObjectContext, and sets the properties from the dictionary to the object:
+(CoreDataClass *) coreDataObjectWithDictionary:(NSDictionary *) spec {
CoreDataClass *myInstance = [NSEntityDescription insertNewObjectForEntityForName: #"CoreDataClass" inManagedObjectContext: [myMOCProvider sharedMOC];
myInstance.someProp = [spec valueForKey:#"someProp"];
}

Why is it not recommended to allocate and initialize with id?

In the following example, what are the possible problems that can occur.
id c = [Person alloc];
[c init];
The main problem with the code in your example is that in some cases, the -init method returns an object that's different from the one that you created with +alloc. If that happened, then your code would be incorrect because you're not assigning the result of [c init] to c, and you'd end up working with the wrong object (and one that's not properly initialized at that). This is why the standard idiom is to always combine +alloc and -init on the same line:
id c = [[Person alloc] init];
Now, you may have written the Person class and have first hand knowledge that -init always returns the same object, but I shouldn't have to be intimately familiar with the inner workings of Person to read your code and have a sense of whether it's correct or not. Your code is "better" in the sense that anyone can tell that it's doing the right thing if you follow the usual convention.
I don't think it's horrible to declare c as type id, but it does seem silly in this case. You know that c will be of type Person*, so why declare it as id and throw away useful information that the compiler can use to help you write better code? If there's a good reason to use id, that's fine, but if you can be more specific about the type you should do so.
When using the id generic type, you won't get a warning if you try to call a method that doesn't exist. The compiler assumes you know what you're doing.
Otherwise, no issues that I can think of. It's common in several situations (think fast enumeration on heterogeneous container type)
Another potential danger is that over time, you may add logic that accidentally only does init for certain cases... leaving an object that is allocated but never initialized means all values in it are essentially random and any setup code it was meant to do is not done.
First of all, type casting problem. Every time you want to use 'c', you may need to (Person *), i.e. typecast it.
secondly, if you have any method declared in Person, you can not call it as [c aMthod] style, you have to use, [(Person *) c aMethod].

vs [mpk5 weaponAttachments]

I'm able to make the method for the call [self weaponAttachments:mpk5] but I don't like having to call self. I think [mpk5 weaponAttachments] is more natural and is easier to read.
The problem I'm having is I need to pass in the weapon (mpk5) in order to use it, which I can do with the first method but not with the second one. Does this mean that I need to subclass NSDictionary in order to be able to use a statement like [mpk5 weaponAttachments]? If so, how do I get ahold of the caller "mpk5" so that I can use it inside the method?
EDIT
I apologize for not putting this in the first time but my objective is to have [mpk5 weaponAttachments] return an NSDictionary or NSArray. Right now I have NSDictionary *attachments = [self weaponAttachments:mpk5]; which works but it just doesn't seem like the best approach.
So firstly, your two calls are a little mixed up:
[self weaponAttachments:mpk5] calls the weaponAttachments method, passing in the variable mpk5.
But [mpk5 weaponAttachments] is either asking the mpk5 object to return the weaponAttachments property or is asking the mpk5 object to run a method called weaponAttachments (I'm simplifying here - it's always a method, but if you're using properties you probably won't realise this as Objective-C will create them for you).
These are fundamentally different things.
On to the brunt of your question:
I don't like having to call self
...unfortunately, if you're working in an object-oriented language you're going to have to get used to this. Say I have a class called mySimpleClass, and a method inside that class called doSomething. Writing this:
[mySimpleClass doSomething] would be what we call a static method. Whereas calling [self doSomething] from within an instance of mySimpleClass would be an instance method.
If you're unsure of the difference between static and instance methods you should probably step back and take a look at some of the basic guides out there.

Reflection in Objective-C (iPhone)

I want to populate [MyClass class] from a JSON string.
I use json-framework to get the NSDictionary, and it's dead easy to instantiate and setValue: forKey:... on my data object.
But for more complex data objects with classes as members of MyClass,
ie:
MyOtherClass *classNoTwo
I tried with
Class test = object_getClass(myClass.classNoTwo);
id foo = [[test alloc] init];
But foo is nil/null. The only way I found to get around it is to in my init method of MyClass is to alloc memory for it, and later replace it.
I would also like to know how to get rid of the myClass.classNoTo reference, as I am not supposed to know all the properties in my general parser.
Please don't just tell me to read the documentation, because I've done that, and I can't figure it out.
Thanks in advance
Try calling class_getProperty() to access a property of a particular name and then property_getAttributes() on the property returned by the first function. This will return a string that encodes the property's attributes, including the type. The format of the string is explained in Property Type Strings in the documentation.
Finally, when you have derived the type of the property, use NSClassFromString() to instantiate an object.
Also see the docs for the two functions mentioned for more details.
I have written a very simple dependency injection container called Factory. I do not get your question entirely, but the problems we solve look similar. Take a look at my sources, they are very simple and should get you started. You might be interested especially in the ClassAnalyzer class. It’s just a hack, but you should be able to get what you want from there.

How to tell if an object has already been allocated, so it isn't allocated multiple times?

Please be nice.. I am a noob with this stuff. I want to allocate and use an object through a method that I call many times, and instead of making it a global variable and allocating it in my initWithFrame method I want to alloc it in just the one method, and make it a local variable that I allocate then and use then.
You need to step back and think about how many different things need to access said object.
If it is everyone, then you should likely implement the shared instance pattern. Something like:
+ (MyObject *) mySharedObjectThatEveryoneUses
{
static MyObject *sharedInstance;
if (!sharedInstance) {
sharedInstance = [MyObject alloc];
sharedInstance = [sharedInstance init];
}
return sharedInstance;
}
Note that the above does not account for threading on initialization. I.e. if multiple threads simultaneously call the method for the first time, you might end up with multiple instances. Also note that the splitting of +alloc and -init is a pattern that is unique to this situation. Doing so avoids the situation where the -init method causes + mySharedObjectThatEveryoneUses to be invoked, creating a second instance before the assignment can happen.
Now, if you are talking about access within an object graph; access to the single instance within some subset of objects in your application, then you will need to have an instance variable somewhere that all of the objects can get to.
For example, say you are implementing a game where there is a Player object and that Player object has a bunch of Piece instances. When a Piece is created, you would typically have a property that refers to the owning player and that would be your single point of reference.
If you need something more transient, you should likely look to what should be your controller layer. I.e. there has to be some object somewhere that can act as a coordinator for the set of objects that need access to that single instance.
If I understood your question correctly, you're looking for a static variable. A static variable keeps its value like a global variable, but it "lives inside" a function like a local variable. Your function could look something like this:
+ (MyObject *)getSingletonObject {
static MyObject *obj = [[MyObject alloc] init];
return obj;
}
obj would be created the first time you called this method, but calling the method again would return the same object it had already created.
What you want is called a Singleton. You can read up on Apple's recommended way to create singletons here:
http://developer.apple.com/Mac/library/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html#//apple_ref/doc/uid/TP40002974-CH4-SW32
Look for "Creating a Singleton Instance" in the "Cocoa Objects" section. There are a few more methods it's good to define beyond just a class level initializer.
I'm not entirely sure I understand your question, but you can't really allocate the same object many times.
Each time you want a new instance, you ask the Class object to allocate a new instance for you (yes, classes being objects themselves is mind blowing). So this code:
NSString* s;
s = [[NSString alloc] init];
s = [[NSString alloc] init];
Here you are creating two instances of NSString. This code is bad because we have alloc'd the first instance and have not released, and assigned its only reference (s) to a new instance. This would cause a memory leak.