Question

How would I turn this:

xmlObject *system_domain  = [xmlObject alloc] 
xmlObject *system_description = [xmlObject alloc]
xmlObject *system_type = [xmlObject alloc]

Into something where I would only have to write xmlObject and [xmlObject alloc] once.

xmlObject *system_domain, *system_description, *system_type = [xmlObject alloc]

This makes all of them xmlObjects, but does not allocate each one. Any help would be much appreciated.

Was it helpful?

Solution

If you've got a set of related objects, and being able to iterating over them is more important than being able to access them concisely, you should stick them in a collection:

NSMutableDictionary *system_info = [NSMutableDictionary dictionary];
for (id key in @[@"domain", @"description", @"type"]) {
  system_info[key] = [xmlObject alloc];
}

Then, instead of system_dictionary you use system_info[@"dictionary"]. (You could even use KVC to make things more concise, if that's important.) Of course if that doesn't fit your use case, it would be silly to stick them in a dictionary in the first place.

In any other use case, what you've done is the normal, idiomatic Objective C way to declare three xmlObjects. If you really want to know if there are ways around it, of course there are, but most of them are pretty silly.

A better solution might be to switch languages. Python, Ruby, Applescript, ObjC++, eero, etc. all let you access the ObjC runtime just as easily as ObjC, and have more concise idiomatic ways of doing things. For example, in Python:

system_domain = xmlObject.alloc()
system_description = xmlObject.alloc()
system_type = xmlObject.alloc()

Or even:

system_domain, system_description, system_type = [xmlObject.alloc() for _ in range(3)]

Another reasonable option, if you have to initialize 500 of these things in a row, is to write some simple code that generates your ObjC code.

But if you really want to stay in ObjC, here are some of the silly solutions:

You can cut the number of xmlObject appearances from 6 to 4 just by doing this:

xmlObject *system_domain = [xmlObject alloc],
     *system_description = [xmlObject alloc],
            *system_type = [xmlObject alloc];

Or to 3:

id system_domain = [xmlObject alloc];
id system_description = [xmlObject alloc];
id system_type = [xmlObject alloc];

Or to 1:

Class x = xmlObject;
id system_domain = [x alloc];
id system_description = [x alloc];
id system_type = [x alloc];

Or:

id makeXmlObject() { return [xmlObject alloc]; }
...

id system_domain = makeXmlObject();
id system_description = makeXmlObject();
id system_type = makeXmlObject();

A few side notes:

You probably don't want to use the result of [xmlObject alloc]. That's a block of enough memory to construct an xmlObject, connected to the xmlObject class, but otherwise completely uninitialized. You have to call an initializer—typically -[init], but often something like -[initWithValue: andOtherValue:]—before you can do anything useful with it.

So, most idiomatic ObjC code will be full of calls like this:

Foo *foo = [[Foo alloc] init];
Bar *bar = [[Bar alloc] initWithFoo:foo];

Also, unless you're using ARC (or GC), you usually want to autorelease the object as soon as it's initialized; otherwise, you have to manage the memory manually (and that's as hard to do properly as it is to say 10 times fast). So, if you ever have to deal with non-ARC code, you'll see this:

Bar *bar = [[[Bar alloc] initWithFoo:foo] autorelease];

Fortunately, many classes provide class constructors that do everything in one:

NSString *s = [NSString stringWithUTF8String:c]; // ARC or no ARC

You should use these convenience methods when they exist, but get used to the alloc] init]; (and alloc] init] autorelease];, if you ever have to deal with pre-ARC/pre-GC code) idiom, because you will need it.

The same is true in all other languages with ObjC runtime bindings; e.g., in Python, you do Bar.barWithFoo(foo) when possible, Bar.alloc().initWithFoo_(foo) otherwise.

Meanwhile, the reason you can't something like this:

xmlObject *system_domain, *system_description, *system_type = [xmlObject alloc];

… or …

system_domain = system_description = system_type = [xmlObject alloc];

… is that the only reasonable interpretation of this would be to set all three objects to the same instance of xmlObject. If you only call alloc once, only one thing gets allocated.

Finally, it's considered bad style to name ObjC classes with a lowercase first letter; it should be XMLObject (or maybe XmlObject, but Apple likes to make acronyms and initialisms explicit), not xmlObject. And, except in very simple projects, most people like to give all of their classes a 2- or 3-letter prefix (like Apple's NS), to make it possible to distinguish classes coming from different subprojects, third-party libraries, etc., so 'ALIXMLObject` might be even better.

OTHER TIPS

You'd have to do something like:

xmlObject *system_domain = [xmlObject alloc],
     *system_description = [xmlObject alloc],
            *system_type = [xmlObject alloc];

Which is hardly better than your first version.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top