How to call encodeWithCoder - objective-c

Possibly a nooby question - how is encodeWithCoder called? I need to use this to save objects in files on the iphone, I am just unsure of how it is actually called. Do I have to manually call it? If so, what do I use as input for the NScoder argument?

You don’t call it yourself, you use NSKeyedArchiver instead:
NSData *serialized = [NSKeyedArchiver archivedDataWithRootObject:foo];
Where foo is your object that conforms to NSCoding. There’s also a method to save the archived object directly to a file.

Related

Searching Functions in Objective C

I have a strange task. I need to get an array that contains all the functions in an objective c object. I then need to be able to tell if each function is a class method or not. Then I need to get the names (preferably an NSString) of each parameter and the type each parameter takes. Is there a way to do this? If not, does anyone know how to access the keys and values coded in the NSCoding Protocol function -(void)encodeWithCoder:(NSCoder*)aCoder; without using NSKeyedArchiver? What I am trying to do here is display a list of properties required to initialize an object. All my objects use class methods to initialize themselves. I am making a level editor that allows me to edit properties that differ between objects and I don't feel like writing getPropertyList and initWithProperties functions for every single object since I have already done this by implementing the NSCoding protocol.
I need to get an array that contains all the functions in an objective c object. I then need to be able to tell if each function is a class method or not.
Easy enough: you want class_copyMethodList(), which gets you just the instance methods for that class. To get the class methods, pass the class object, e.g. class_copyMethodList(object_getClass([NSString class]), &count);
Then I need to get the names (preferably an NSString) of each parameter and the type each parameter takes.
The parameter name part is probably not possible. They're not included in the method's metadata, and I'm pretty sure that they don't survive compilation at all; digging them out of the executable if they're there would certainly not be easy.
The types, however, are easily accessible via one of two runtime functions: either method_getTypeEncoding(), which gets you the signature string for the method's return and arguments, or method_getArgumentType(), which will let you loop over the argument types (the returned strings use the same code as the full type string).
If not, does anyone know how to access the keys and values coded in the NSCoding Protocol function -(void)encodeWithCoder:(NSCoder*)aCoder without using NSKeyedArchiver?
Are you talking about the particular implementation that you've made for encodeWithCoder:? You want the list of ivars implied by [coder encodeObject:firstIvar forKey:#"firstIvar"]; [coder encodeObject:secondIvar forKey:#"secondIvar"];? I'm not sure what that has to do with method signatures, but if so, you could make an NSCoder subclass that creates a dictionary from when you pass it as the coder and send encodeWithCoder: to your objects (see this answer I posted the other day).
What I am trying to do here is display a list of properties required to initialize an object.
What about a class method that returns an array with the names of the properties?
+ (NSArray *)essentialPropertyNames {
return [NSArray arrayWithObjects:#"firstIvar", #"secondIvar", nil];
}
That would probably be less effort than picking through the runtime/class metadata and wouldn't be any less odd.
All my objects use class methods to initialize themselves.
That sounds unusual at best. In Cocoa, instances should use some form of -init to do their initialization.

Cache custom class

In my app I am working with the SimpleKML framework
https://github.com/mapbox/Simple-KML
I have some big files which takes about 5 seconds to process thought this library. I was thinking to cache the object in something like NSData.
I have read this tutorial from Apple:
https://developer.apple.com/library/mac/#documentation/cocoa/conceptual/Archiving/Articles/archives.html
But i dont really know of using nscoder is the best way to do this. Can someone point me in the right direction?
You want to use NSKeyedArchiver and NSKeyedUnarchiver.
If the object you're saving (and the objects it has as properties, and their properties, etc.) implement the NSCoding protocol then it's, as simple as
NSData *savedData = [NSKeyedArchiver archivedDataWithRootObject:someObject];
[savedData writeToFile:pathToSaveFile atomically:YES];
to archive the object into an NSData and then save it to disk, and then later
NSData *loadedData = [NSData dataWithContentsOfFile:pathToSaveFile];
SomeClass *foo = [NSKeyedUnarchiver loadedData]
to load the data and unarchive the object from the data.
If not, you'll need to override initWithCoder: and encodeWithCoder: for the objects in question to make them serialize properly.

NSMutableDictionary vs CFMutableDictionary

I have a requirement for a dictionary with keys that are not copied. This has lead me on a merry dance and I've ended up at the door of CFMutableDictionary.
I am trying to understand the extent to which they are interchangeable. In Apple's docs for CFMutableDictionary they state:
in a method where you see an NSMutableDictionary * parameter, you can
pass in a CFMutableDictionaryRef, and in a function where you see a
CFMutableDictionaryRef parameter, you can pass in an
NSMutableDictionary instance.
But I wondered whether it would be possible to cast a CFMutableDictionary to NSMutableDictionary and call NSMutableDictionary's methods on it, and it seems in some cases you can;
If I create a CFMutableDictionary using CFDictionaryCreateMutable() and cast it to an NSMutableDictionary.
I can call:
[cfDictionaryCastToNSDictionary objectForKey:someKey]
I can also call:
[cfDictionaryCastToNSDictionary setObject:someObject forKey:someKey]
... which will copy the key or raise an exception if it doesn't implement NSCopying. I can also iterate through its values using a for in loop.
However if I call:
[cfDictionaryCastToNSDictionary count]
I get an exception.
My question is what exactly is going on here under the hood? At no point does the Apple documentation mention being able to call some methods that do not exist on CFMutableDictionary by casting to NSDictionary.
If you are looking to understand problems using toll-free bridging, you should start with Mike Ash's "Toll-Free Bridging Internals" and go from there.
If you just want to get back to work, the answer is, don't do that; avoid the problem entirely by using the CF functions with the CFDictionary rather than toll-free bridging. The CFDictionary API should be enough to do whatever you're trying to do if the dictionary is being used purely internally.

NSUserDefaultsProblem

I have a simple problem:
I add an object to an NSArray, then I add an object to it then I use the NSUserDefaults way to save the array, but it doesn't work, I mean the array isn't saved and the console sends me this messange:
2011-03-21 23:09:53.994 Project[10490:207] * -[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '(
""
)' of class '__NSArrayM'.
does anybody know how can I fix this.
NSUserDefaults only allows you to save basic lightweight objects; for example NSString, NSNumber and NSData. If you want to add another class, you'll have to shoehorn it into an NSData object beforehand. This is pretty simple, usually just a call to [NSKeyedArchiver archivedDataWithRootObject:array];. Note that the objects in the array must implement the NSCoding protocol, which you'll have to add to any of your own custom classes if that's what you want to save.
Also keep in mind NSUserDefaults is meant for lightweight preferences, not application data. If you have a large array of objects, you might be better served by archiving it to its own file or using Core Data (if you feel comfortable using something a little more advanced).
The only types you can save in NSUserDefaults are property list types: NSString, NSDate, NSArray, NSDictionary, NSNumber, NSData. You're probably trying to save an array of objects that aren't one of these types.

Storing callbacks in a dictionary (Objective C for the iPhone)

I am trying to store callbacks in a dictionary.
I can't use blocks as the iPhone doesn't support this (unless you use plblocks).
I tried using functions, but apparently NSMutableDictionary doesn't allow these pointers (wants an id)
I tried using class methods, but I couldn't find a way to obtain a pointer to these
I could try using functions with the c++ stl hashmap (if it is supported in Objective C++), but apparently this can slow compilation times.
I could try storing both a class and a selector, but that seems rather messy.
What would be the best way to do this?
You can put it in an NSInvocation.
An NSInvocation is an Objective-C
message rendered static, that is, it
is an action turned into an object.
NSInvocation objects are used to store
and forward messages between objects
and between applications, primarily by
NSTimer objects and the distributed
objects system.
If you know what you are doing with pointers, you can wrap them up with NSValue. You can then put NSValue in a dictionary.
To insert:
[myDict setObject:[NSValue valueWithPointer:functionName] forKey:myKey];
For retrieval:
NSValue* funcVal=(NSValue*) [myDict objectForKey:myKey];
returnType* (*func)()=[funcVal pointerValue];
If it's your own project, why not use blocks since you can?
It is possible to make a single file compile using C++ if you change the extension to .mm. You don't have to change the other files in your project as long as they don't have to handle any C++ types.