What I mean by generic is that you pass a class and a JSON to a method and that method transforms the JSON data in your object based on the class definition.
I'm interested both in conceptual answers and Objective-C approaches.
I assume with generic parser, you mean an implicit JSON-to-object mapper.
In this case, there is one challenge. Which might or might not be solvable depending whether variables are types in Objective-C (it's actually a shame I dont know that). While its quite simple to map setter method names (given Objective-C does provide reflection) to JSON attributes, it is hard to know which object to create for nested JSON objects. So you need a kind of factory that guesses which type nested objects could have. If variables in Objective-C are types, that might be used as a hint, if not you are left on your own.
Getting the data into NSArray and the like is easy, there are plenty of these around, for example json-framework
Try this (untested):
#import <Cocoa/Cocoa.h>
#import "JSON/JSON.h"
int main(int argc, char *argv[])
{
NSLog(#"%#", [#"[ 100, 500, 300, 200, 400 ]" JSONValue]);
return 0;
}
As Adrian says, mapping your data structures to objects is a bit of a challenge, then. It isn't in json-framework, I don't know what else there is. For sure, but I suppose that the project maintainer will accept your code, if you write some :).
You would need to use reflection on the passed in class which is not handled as well as some other languages from what i can see.
Class c = [self class];
Will return a C struct containing a list of variables and methods and then it would be a matter of writing a data mapper style system to reflect the class and assign the JSON variables to it.
E.g. JSON struct of
var x = { prop1: "Test 1",
prop2: "Test 2};
Then have a class
#interface x : NSObject {
NSString* prop1;
NSString* prop2;
}
#property (nonatomic,retain) NSString* prop1;
#property (nonatomic,retain) NSString* prop2;
You'd need to have a concrete implementation but it doesn't need to do anything fancy really.
Your mapper could then use either use reflection to parse the object or just use dumb assignment:
- (NSObject)mapClassFromJSON:(NSObject)class fromJSON:(id)jsonArray
{
//code needs to iterate over the jsonArray (needs to check using isKindOfClass if it's an NSArray or NSDictionary) and assign the class properties to it.
}
Remember if using SBJSON which everyone does, that the types inside the returned JSON can either be NSArray or NSDictionary, it needs to know which. If going down the generic path for nesting then it would need to use variable reflection and some smarts to generate the type mappings as otherwise it needs to be hard coded for each class.
Edit:
Have a look at
http://developer.apple.com/mac/library/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html#//apple_ref/c/func/class_copyPropertyList
Might be useful, might not...
Well, conceptually, this method is known as serialization/deserialization. The difference is that your serialized format will be JSON. Realization: Define basic conventions for your class and JSON and implement them. For example: Every JSON should have uniq-id which will correspond to the class.
I'm not familiar with Objective-C, but if I would do that in other languages, I would assume, that every key in JSON, would represent the attribute of the class. This attribute could be set by function like classInstance.setJsonAttribute(key, value); Then, I would write some JSON parser which would walk through JSON, extracted uniq-id, created class based on this id, and walked through all other key:values parse, setting them with setJsonAttribute function. I think, that would be my begin in implementation.
For others who may come accross this post, it is possible! And there happen to be a few open source projects that already do this very well. Checkout rest kit and
https://github.com/RestKit/RestKit
https://github.com/dchohfi/KeyValueObjectMapping
I dont know objective-c at all but i do know JSON.
Its a uniform data exchange format, with an RFC so you would definately be able to role your own parser. Does objective-c support generic types? If so what your looking for would be achievable, and id also guess that someone else has all ready rolled one.
Related
Imagine this handy method called "cycle":
str = [str cycle:#[#"blue",#"white",#"red"]];
So, the string will cycle through each item of the array, looping around. (If str is not contained in the array, return the same value, let's say.)
Now of course, you could also write such a routine for integers, say, which would be very handy.
cyl = [cyl cycle:#[#(2),#(4),#(6),#(8),#(12)];
and so on.
Another example, it would be handy for enums, something like this:
self.picker.cameraFlashMode=
[self.picker.cameraFlashMode // you can't really do that :)
cycle: #[
UIImagePickerControllerCameraFlashModeOn,
UIImagePickerControllerCameraFlashModeOff,
UIImagePickerControllerCameraFlashModeAuto] ];
How to write a method / function / routine for this so it works for all types?
In other words, it should be possible to do something like this,
x = [x cycle:array];
or maybe some sort of macro like this ...
cycle( x, ..items.. );
no matter what x is. How would you do that?
You could create an NSObject category and implement that function. It would only work with objects inheriting from NSObject.
#implementation NSObject (myCategory)
- (id)cycle:(NSArray *)array
{
// code here
}
#end
This would not work for other types, but you could use C++ Templates to create a function that works for any data type.
template <class type> ret-type cycle(parameter list)
{
// body of function
}
This looks like an antipattern to me. Consider your example:
[str cycle:#[#"blue",#"white",#"red"]];
str is probably defined as an NSString, right? I would consider it a really bad idea for any method on NSString to modify the string in place, given that it’s an immutable class. You’d probably have to define a category on NSObject to get this kind of all-class behavior, but then what about this example?
[self.picker.cameraFlashMode cycle:#[
UIImagePickerControllerCameraFlashModeOn,
UIImagePickerControllerCameraFlashModeOff,
UIImagePickerControllerCameraFlashModeAuto]];
Is cameraFlashMode even an object? Remember, you can’t pass messages to instances of an enum type!
Edited to add…
If you write something like
int a = 1;
then a construction like
[a cycle:#[#1, #2, #3]];
is never going to be valid Objective-C syntax.
Sounds like it might be a good opportunity for an NSEnumerator subclass.
You'd need to implement - (id)nextObject and - (NSArray*)allObjects. The only problem I would see is that an NSEnumerator typically has an exhaustible list of objects, while this would theoretically continue forever.
In Objective-C, is there any way to run a specific selector automatically every time an object is instantiated? (I know about +initialize but I need an instance method).
Specifically, I am writing a custom string class (that inherits from my own root class with a similar interface to NSObject) and I am trying to make it 'play nicely' with Objective-C constant strings. To do this, I have the following class definition (as required by the runtime):
// 1) Required Layout
#interface MYConstantString : MYObject {
//Class isa; inherited from MYObject
char *c_string;
unsigned int length;
}
Now, I want to implement my string class by using a pointer to a C-struct inside the class (this "C object" is already well implemented so I basically just want to wrap it in an Objective-C class). Ideally therefore, my Objective-C class would look like this:
// 2) Desired Laout
#interface MYConstantString : MYObject {
// Class isa;
StringObject *string;
}
And then the class and instance methods would just wrap C function calls using that StringObject.
So because I can't have the desired ivar layout (2), I wish to hack around the required ivar layout (1) to work for me. For example:
- (void)fixup {
// Pseudocode
temp = copystring(c_string);
c_string = (void *)StringObjectNewWithString(temp); // Fudge pointer
length = ... // I can do something else with this.
}
So, to return to the question, is there a way to call -fixup automatically, rather than having to do the following every time I make write an Objective-C constant string?
MYConstantString *str = #"Constant string";
[str fixup];
I know this is an obscene hack, and Objective-C constant string interoperability isn't totally crucial for what I need, but it would be nice to be able to use the #"" syntax and make the code more 'naturally' Objective-C.
I'm guessing you left out an important fact: you're using -fconstant-string-class=MYConstantString when building to have the compiler use your class for constant string objects (#"...").
Given that, then, no. There are two significant problems. First, "instance creation" for constant strings happens at compile time, not run time. The reason that there's a required layout is that the compiler does nothing but lay out the string's data in a data section with a reference to the appropriate class object where the isa pointer goes. It doesn't invoke any custom code. It is not necessarily even aware of such custom code at compile time. A given translation unit may not include the constant string class. The reference to that is resolved at link time.
Second, the constant string instance is almost certainly laid out in a read-only data section. There's a good chance that even calling your -fixup method manually as in your question would encounter an access violation because you'd be modifying read-only memory.
You should consider using a class cluster. Make MYConstantString one concrete subclass of an abstract base class. Make it conform to the required layout and just use the character pointer and length ivars as they are. If it would be convenient to translate to StringObject at various points, do that at those points. Implement other, separate concrete subclasses to use StringObject internally, if desired.
MYConstantString *str = #"Constant string";
That can't work because #"..." is an NSString, and it's not only a problem of layout but of instance sizes. If you want 0-copy or anything like that, what you have to do is have something like:
MYConstantString *str = [MyConstantString stringWithNSString:#"Constant string"];
and let -stringWithNSString: recognize when the passed string is a constant one (I'm pretty sure the concrete class of constant strings is easy to recognize, and probably hasn't changed ever for backward compatibility reasons) and then hack it around to grab the pointer to the bytes and similar things.
In ObjC we can use protocols to restrict an id behavior, so we can declare something like
-(void)aMethod:(id<aProtocol>)aVar which works very well until we provide a value or a non-id variable as aVar, but this gets completely broken since we can pass a generic id variable delcared without protocols specifiers... Is this normal? Is there any workaround? Am I missing something?
Just use id less, and declare variables and parameters using the correct types, where possible. That is to say: don't pass ids around. If you are implementing a collections class (for example), then id's often useful.
My approach is to specify types, and introduce that type as local as possible in the source. So I omit id and add the type, and when (for instance) I take a reference from a collection, I create a variable:
MONType<MONProtocol>* thing = [array objectAtIndex:idx];
// now thing is correctly typed. use thing.
Similarly, if I have an id parameter, I declare a new variable:
- (IBAction)someAction:(id)sender
{
NSButton * button = sender;
// now use button, not sender
Protocols are extremely useful. Very often, better/cleaner than subclassing.
You're missing the understanding that types in Objective-C are determined at runtime, not compile time. Just because you say that an object will be of type id<aProtocol> does not mean that at runtime it is guaranteed to be so.
The idea of specifying something as id<aProtocol> is to aid you as a developer and people using your code. It aids you as a developer because the compiler will warn (or error under ARC) if you attempt to call a method on something that the compiler can determine it doesn't think exists on instances of its supposed type (excluding forwarding which could mean an instance responds to something the compiler cannot determine). It aids people using your code as it tells them the contract that they should adhere to when interfacing with your code.
So, in your question you say that:
but this gets completely broken if we pass a generic id variable delcared without protocols specifiers
Well, the compiler would warn and tell you that you're trying to pass something that does not conform to that protocol, except for the case of passing id. That's why you generally should try to type things more precisely than just id.
If you have a method defined like so:
- (void)aMethod:(id<aProtocol>)aVar
Then aVar could be of type SomeSubclass where that is defined like so:
#interface SomeSubclass : NSObject <aProtocol>
And you could then use aMethod like this:
SomeSubclass *obj = [SomeSubclass new];
[other aMethod:obj];
I (FINALLY) found out that using Objective-C++ is the way to go. Let's suppose I want to be able to pass NSString or NSNumber (instead of a too much generic id and instead of using protocols which become useless passing id values): well, I can create a C++ class having two distinct constructors, one for each ObjC class, so passing id values cannot be done anymore (almost directly). For example, let's take a look at
class NSStringOrNSNumber{
public:
NSStringOrNSNumber(NSString *);
NSStringOrNSNumber(NSNumber *);
};
The great advantage is that methods/functions taking a NSStringOrNSNumber parameter can get NSString/NSNumber values DIRECTLY, since the constructor acts as an implicit cast. In other words, if we have
void aFunction(NSStringOrNSNumber param);
the following calls are perfectly valid:
aFunction(#"Hello!");
aFunction(#25);
The only (little) downside is that we need the class to implement a function if we want to get back the value passed to the constructor.
Using a C++ class constructor to get something like id<NSCoding> is still better the using id<NSCoding> directly: in fact, if we do the following
#class classOne, classTwo;
class NSCodingClass{
private:
NSCodingClass(classOne *);
NSCodingClass(classTwo *);
public:
NSCodingClass(id<NSCoding>);
}
we won't be able to pass a generic id as a parameter (since it would be ambiguous: the compiler cannot know which constructor to call among the two private ones)
I am new to Obj-C so forgive me if this is a stupid question:
How do I implement some in the style of Javas enums? Or to be more precise:
I want a class with some known properties which are fix at compile time and unique per instance. Additionally I only want one instance type.
Let me give an example in Java:
public enum MessageTypes {
DEFAULT("white", "standard", 1),
EXPRESS("red", "expressMessage", 2),
BORADCAST("green", "broadcast", 3);
String color; String tagName; int dbId;
MessageTypes(String color, String tagName, int dbId) {
// you get the idea
}
//some methonds like getEnumByTagName
}
How would you do something like this in Objective-C? Am I missing something? Is this a bad pattern at all?
Thanks in advance!
EDIT: I am sorry, if I did not made myself clear. I know, that obj-c enums are not what I am looking for (as they are only marginally more than a typedef to an int).
I would like to create a set of (kind-of-singleton, immutable) instances of a specific class. The singleton pattern in Apples Dev-Docs is of no use as I want multiple distinct instances of a class each with individual values in their properties.
The goal of that is to have multiple Message types (about 20) that can be assigned to a Message as a property. Each of my Message types has a (fix and predefined) color, attribute-value (in an XML-representation) and a numerical ID.
In Java, I would use an enum as in my code sample. But how do I create different MessageTypes and associate them with their properties in Obj-C?
Creating 20 Sublcasses of MessageType (each with a singleton-instance holding the properties) seems like a lot of work for such a simple task and total overkill.
My current approach is to create a class with an NSArray holding the different instances. Up on first access of a method like +(id)messageTypeForId:NSInteger id_ the NSArray is prepopulated. But this feels totally clumsy and not at all elegant...
Is there a more satisfying approach?
There is not much in the way of a "more satisfying approach".
The normal Cocoa pattern would be to create methods like:
+ (MessageTypes*) sharedDefaultMessageType;
+ (MessageTypes*) sharedExpressMessageType;
+ (MessageTypes*) sharedBroadcastMessageType;
etc
and then implement them something like:
+ (MessageTypes*) sharedDefaultMessageType
{
static MessageTypes* thisMessageType = nil;
if ( !thisMessageType ) {
thisMessageType = [[MessageTypes alloc] initWithColor:#"white" tagName:#"standard" dbId:1];
}
return thisMessageType;
}
Alternatively, storing the shared MessageType* in an NSMutableArray or NSMutableDictionary or precalculating them as you are doing are all equally valid approraches.
Note that the above "template" method could be generated via a macro such that you could write in the .m file:
CREATEMESSAGETYPE( Default, #"white", #"standard", 1 )
CREATEMESSAGETYPE( Express, #"red", #"expressMessage", 2 )
CREATEMESSAGETYPE( Broadcast, #"green", #"broadcast", 3 )
which might be "more satisfying" or more ugly, depending on your point of view.
I think I'd just use a standard C enum:
typedef enum { MT_WHITE, MT_RED, MT_GREEN } MessageType;
Then you just use it as you would any other data type:
#interface Blah {}
-(void) setMessageType:(MessageType)newMessageType;
#end
Enums are not objects in C, and thus not in Objective-C either. They're just user-defined scalars that have a limited set of named values that they can take. You can give an object properties that are enum types, which I think is closest to what you're looking for.
If there's something specific you need to accomplish with this functionality, you might want to edit your post to indicate what that is.
I had the same question more or less but find all the above solutions clumsy stylistically.
In particular when simply using a C enum property on an object you lose the singleton semantics of Java enums. The biggest freedom I have found in the use of Java enums is that the instances of an enum are really singleton subclasses, and so participate in method polymorphism. Even more powerful than enums with unique attributes is enums with polymorphic behaviour.
Given that this is the key feature I am after would an Objective-C class cluster with singleton private subclasses be an approach with the desired behaviour, despite being a bit over the top in implementation cost and complexity?
In Java, it is very easy to code the following design:
public abstract class Pizza {
public static final Pizza.NULL = new Pizza() {
/* "null" implementations */
}
/* actual/abstract implmentations */
}
What is the preferred method to attain the same efficient scenario in Objective-C? I have been unable to find any documentation on the subject, and I have tried a couple different scenarios with static const, #define etc. but none of them seem to work out as well as the Java method above.
I would like to avoid writing a concrete NullPizza class that has a static method to obtain the singleton instance, as it seems more 'proper' for it to be some final property/field of the highest-level interface. (Pizza, in this case.)
Edit: While I understand how the NULL pattern specifically would be handled due to Obj-C's unique method of handling method calls to 'nil', what about other static common instances, such as Response.YES and Response.NO? (See comments for discussion.)
There is no need for this type of pattern in Objective-C because it is not considered a runtime error to message a nil instance of a class. If the method has a defined return type, there are defined returns from messaging a nil object (e.g., methods that return an integer return 0 when messaging a nil object).
There are two things which can help here. The first is nil, the Objective-C equivalent of the Java NULL pointer - it can actually receive messages and respond to them. It will always return nil if the return value is an object, and 0 if the return value is some primitive type. Therefore if the Null behaviour of your object is "do nothing" you can easily just use nil as the Null value.
The other thing which is helpful is for when you need to store a placeholder or null value in a container object - these usually throw exceptions if you attempt to add nil as a value. Instead you can use the singleton +[NSNull null], which does nothing except act as a "this space intentionally left blank" object.
With these two weapons at your disposal there should be no reason to write a null instance of a custom class :-)
For your Response.YES and Response.NO, I assume you have instances that you do want to change, rather than just making all Response properties read-only.
A common pattern in Cocoa is to have both immutable and mutable versions of a class (NSArray versus NSMutableArray). For your response example, it would make sense to have an immutable Response class that has the static YES and NO methods, and a MutableResponse subclass that exposes setters for those times where you do want objects to change them. Does this cover your second example?
I don't think there is an easy way to provide this implementation. You're asking for something that is a language feature of Java to be implemented in Objective-C - you can do it but you have to write the code that is in the Java runtime yourself - there is nothing to stop you doing this but it's not something the language has built in.
It's a bit like asking "How do I show a Windows style 'one menu per window" UI in Cocoa' - you can do it but it's not provided for free from the framework. Or, "how can I easily implement Objective-C's nil pointer handling in Java?"
If you really want to see this type of functionality I think you should follow the NSArray/NSMutableArray design pattern. Declare a superclass that can handle all of your special cases:
#interface NullPizza : NSObject
{
}
- (BOOL)areYouANullPizza;
#end
and then subclass with your real Pizza and include a newNullPizza class method (which is just syntax sugar):
#interface Pizza : NullPizza
{
}
+ (Pizza*)Null;
#end
#implementation Pizza
+ (Pizza*)newNullPizza
{
return [[NullPizza]alloc init]; // Singleton code left as an exercise.
}
- (BOOL)areYouANullPizza;
{
return NO;
}
#end
Note that if you wanted to implement a +(Pizza*)NULL method on Pizza you should autorelease the new NullPizza you create.
Disclaimer, I typed this code straight into SO. I'd be surprised if it compiles but you get the idea.