Line of code from Swift to Objective-C - objective-c

I'm quite blank when it comes to swift, I've been developing using Obj-c. But a tutorial that I've been following uses Swift. Can anyone help me convert the following line of Swift into Objective-C. It's basically to load a String onto an Array.
self.iDArray.append(objectIDs[i].valueForKey("objectId") as! String)

self.iDArray.append(objectIDs[i].valueForKey("objectId") as! String)
Should be
[self.iDArray append: [objectIDs[1].valueForKey: #"objectID"]]
However, the Swift code is force-casting [objectIDs[1].valueForKey: #"objectID"] to type String (A Swift string).
That suggests to me that self.iDArray may be a Swift array. Swift arrays normally contain only a single type. You create an array of String objects, or an array of Dictionary objects. You can also create an array of AnyObject.
NSArray is an array of id type.
I'm not 100% positive how to force-cast to String type in Objective-C. maybe:
[self.iDArray append: (String) [objectIDs[1] valueForKey: #"objectID"]]

On the surface, objectIDs[x] appears to be a dictionary, and the compiler will give you a break on types if you dereference it that way. So naive to parse, a usable syntax would be:
[self.iDArray append:objectIDs[1][#"objectId"]];
But that's incorrect semantically for parse, since the implication is that the objectIDs array is implied to contain parse objects (named confusingly with the "IDs" suffix). If it's really parse objects, then the collection style reference for objectId won't work, and should be instead
[self.iDArray append:((PFObject *)objectIDs[1]).objectId];
Or more readably:
PFObject *object = objectIDs[1];
NSString *objectId = object.objectId;
[self.iDArray append:objectId];
But, along the same lines semantically, the implication of the code is that it's adding to an NSMutable array, so it probably should be -- for any of the above suggestions:
[self.iDArray addObject: .....
Stop reading here if you care only about compiling and executing without a crash.
But, even if all that's right, which I think can be inferred from the code, it's indicative of bad design in my opinion. Swift developers in particular seem to have a penchant for saving off objectIDs and passing them around as proxies for object, and in so doing, loosing all of the other valuable stuff in the PFObject.
My practice is, wherever possible, just keep and pass the whole PFObject. You can always ask it for its objectId, later. More strongly, my rule of thumb when reading code is: show me parse.com code that refers much to objectIds -- except for things like equality tests -- and I'll show you a design error.

Related

Objective-C = operator vs stringWithString/arrayWithArray

I'm new to obj-c development but partly have background in C development. It might be a noob question but I couldn't get an exact answer in other places. What is the difference between these snippets for arrays and strings and possibly other types of objects:
NSArray *original = [NSArray arrayWithObjects:someObjects,nil];
//Case 1
NSArray *copy1 = original;
//Case 2
NSArray *copy2 = [NSArray arrayWithArray:original];
and for strings
NSString *original = #"aString";
//Case 1
NSString *copy1 = original;
//Case 2
NSString *copy2 = [NSString stringWithString:original];
If I make changes to copy1 and copy2 later will they be reflected on original objects? And does the same rules apply to other object types?
The second code snippet does for NSString what the first code snippet does for NSArray. There is no difference in the behavior, because both NSString and NSArray objects in Cocoa are immutable.
When you call [NSString stringWithString:original], Cocoa is smart enough not to create a new object: the reasoning behind this decision is that since original cannot be changed, there's nothing you could do to tell apart a copy from the original. Same goes for [NSArray arrayWithArray:original], because you get the same instance back.
Note: If someObjects is mutable, one could tell apart an array from its deep copy by modifying the object, and seeing if it changes in the other place. However, arrayWithArray: method makes a "shallow" copy, so you wouldn't be able to detect a difference even if the objects inside your array are mutable.
Your question is really about what objects pointers are pointing to. When you say make changes to copy1 and copy2 later, I guess you mean to the pointer contents, not to the object referenced by that pointer. This is a rather functional way to think, but it important non-the-less.
In your example, the array / string part doesn't matter, because you aren't doing anything with the objects, you are just doing things with the pointers to those objects.
original points to one object. copy1 points to the same object. copy2 points to a different object (but which, in this case, is a copy of the first object).
copy1 is not a copy, but another pointer to the same memory as original. copy2 is actually a copy, pointing at a different piece of memory.
If you modify copy1 (assuming it was mutable, which you example code is not), you are modifying original too, as they point at the same piece of memory.
If you modify copy2, original should be unchanged (generally speaking). In your array example, the objects in the array original and in the array copy2 are, I believe the same. So you in this case, you have two arrays, but they have in them the same objects.
NSArrays and NSStrings are immutable so you can't change them.
You can't add or remove objects from NSArray, but if you change some object in array, it will change in its copy because NSArray holds a pointer to it.

Objective-C Containers that take objects

I'm doing my first steps in objective-c (after a long, long time away from it) by translating some Java code I wrote for an Android game. It seems like there is no container that can take an object, without casting it to id first? Or is there?
Specifically this is the code I'm trying to work with:
NSMutableArray *touchedBodies = [[NSMutableArray alloc] init];
// some additional code
if(![touchedBodies containsObject:(id)body]) {
[touchedBodies addObject:(id)body];
}
The containsObject line passes fine, but on the touchedBodies addObject:(id)b I'm getting a "bad access" error. The body I'm trying to add is a legitimate Box2D b2Body.
When I tried to add the body directly, without casting it:
[touchedBodies addObject:body];
the compiler complains "Cannot initialize a parameter of type id with an lvalue of type b2Body* '
What am I missing?
First of all you never need to cast to an id type just because you can consider id as the Object class in Java: it's an implicit upcast that doesn't need to be explicit.
In second instance the problem occurs because 2dBody is a C++ class, not an Objective-C class. While you can mix Objective-C++ and C++ code (the former is a superset of the latter), you can't mix objects from these two languages without some workarounds.
You have mainly three solutions:
if 2dBody is a pointer, wrap it inside an NSValue: [touchedBodies addObject:[NSValue valueWithPointer:body]], this introduces some overhead with object allocations and you will need to cast it when you use it, 2dBody *b = (2dBody*)[value pointerValue]
if 2dBody is not a pointer then you could use an NSData: [NSData dataWithBytes:.. length:..], this introduces overhead, problems with memory management (unless you use noCopy variants), it introduces problems if the layout of the class is not standard, and you will need to cast it in any case
forget cocoa collections and use STL collections, they're more performant and they will manage everything seamlessly: vector<2dBody> touchedBodies; touchedBodies.push_back(body);.
I strongly suggest using STL collections, I personally use this approach

An Array of Blocks?

This seems like a very strange interaction to me but at the same time it not only works but throws no warnings or errors in the process. Just looking to get some better understanding of blocks in general and why something like this could be right or wrong.
Is there any reason why something like this shouldn't be done?
NSArray *array = [NSArray arrayWithObjects:^{NSLog(#"Block 1");}, ^{NSLog(#"Block 2");}, ^{NSLog(#"Block 3");}, nil];
for (id block in array) {
[block invoke];
}
Putting Blocks into NSArrays is fine; they're objects. In fact, they inherit from NSObject.
You do need to copy, them, however. Those Blocks are created on the stack and need to be moved to the heap in order to live past the end of the current method. If you're using ARC, this is easy:
NSArray *array = [NSArray arrayWithObjects:[^{NSLog(#"Block 1");} copy], ...
Under MRR, you need to balance that copy, so you have two unpleasant options: use temps, or enumerate the array right after creating it and send release to all its members.
Sending invoke, on the other hand, isn't completely kosher, because that's a private method. The only fully-API-compliant way to invoke a Block is with function-call syntax:
typedef GenericBlock dispatch_block_t;
for( GenericBlock block in array ){
block();
}
Sure, that's fine. Why wouldn't it be fine?
In languages like JavaScript this technique is commonplace when registering event handlers.
object.clickHandlers.push(function() { doStuff() });
object.clickHandlers.push(function() { doMoreStuff() });
I see no reason that similar techniques couldn't be used with ObjC blocks, as they are real objects.
The more interesting question to me though, is if this pattern is the best choice for whatever your goal is. Which you haven't really told us.
Blocks in Objective-C are "first-class citizen" objects. Whatever you can do to a regular object, be it passing as a parameter, storing in an array or a dictionary, and so on, you can do it to block objects as well.
For example, an array of block objects may be useful to encode a sequence of actions that is not known at compile time; a dictionary of block objects keyed by strings could be useful in implementing a scripting language, and so on.
The best way to call a block retrieved from a collection is casting it to its proper type, and using the regular block invocation syntax on it.

How can I name an obj-c function to call in xml data

Newbie question here. I'd like to be able to specify through data (i.e. an XML file), the appropriate Objective-C message to send. Any advice on if this is possible or how I can do this?
The next best thing, if I can't do this, would be some way to create a map object that would correlate a key (an int) with a function (I guess also a selector). Is that possible if the above isn't?
If someone could point me to some tutorial or example code as reference, that'd be great. Right now I'm doing things with a big switch statement, and I don't like it. (I'm switching on the id and in each case, explicitly calling the method relevant to the particular id.)
I love that you asked this question; too often, I see Satan's Swollen Switch Statement. It's nice to see someone wanting to using a function-table instead.
If you're OK with using a property list file (which is usually encoded in XML), this is really easy.
Just make a property list where the root element is a dictionary, which maps from some keys to some selectors.
Key Type Value
----------------------------------------------
Root Dictionary
firstKey String someSelector
secondKey String anotherSelector
Load the contents of your property list into an NSDictionary:
id path = [[NSBundle mainBundle] pathForResource:#"filename" ofType:#"plist"];
id dict = [NSDictionary dictionaryWithContentsOfFile:path];
SEL selector = NSSelectorFromString([dict objectForKey:#"firstKey"]);
if ([someObject respondsToSelector:selector]) {
[someObject performSelector:selector];
}
Of course, you'll want to refactor this logic into an appropriate method, and probably cache the property list as an instance variable.
Note: I personally think it's better to just put this function table inline; property lists are cool, but I'm not sure that it is very helpful in this case. Also, if you are cool with using Objective-C++, std::map will allow you to get away with not wrapping and unwrapping the selectors in NSString objects, etc.

Cocoa: Testing to find if an NSString is immutable or mutable?

This produces an immutable string object:
NSString* myStringA = #"A"; //CORRECTED FROM: NSMutableString* myStringA = #"A";
This produces a mutable string object:
NSMutableString* myStringB = [NSMutableString stringWithString:#"B"];
But both objects are reported as the same kind of object, "NSCFString":
NSLog(#"myStringA is type: %#, myStringB is type: %#",
[myStringA class], [myStringB class]);
So what is distinguishing these objects internally, and how do I test for that, so that I can easily determine if a mystery string variable is immutable or mutable before doing something evil to it?
The docs include a fairly long explanation on why Apple doesn't want you to do this and why they explicitly do not support it in Receiving Mutable Objects. The summary is:
So don’t make a decision on object
mutability based on what introspection
tells you about an object. Treat
objects as mutable or not based on
what you are handed at the API
boundaries (that is, based on the
return type). If you need to
unambiguously mark an object as
mutable or immutable when you pass it
to clients, pass that information as a
flag along with the object.
I find their NSView example the easiest to understand, and it illustrates a basic Cocoa problem. You have an NSMutableArray called "elements" that you want to expose as an array, but don't want callers to mess with. You have several options:
Expose your NSMutableArray as an NSArray.
Always make a non-mutable copy when requested
Store elements as an NSArray and create a new array every time it mutates.
I've done all of these at various points. #1 is by far the simplest and fastest solution. It's also dangerous, since the array might mutate behind the caller's back. But Apple indicates it's what they do in some cases (note the warning for -subviews in NSView). I can confirm that while #2 and #3 are much safer, they can create major performance problems, which is probably why Apple has chosen not to use them on oft-accessed members like -subviews.
The upshot of all of this is that if you use #1, then introspection will mislead you. You have an NSMutableArray cast as an NSArray, and introspection will indicate that it's mutable (introspection has no way to know otherwise). But you must not mutate it. Only the compile-time type check can tell you that, and so it's the only thing you can trust.
The fix for this would be some kind of fast copy-on-write immutable version of a mutable data structure. That way #2 could possibly be done with decent performance. I can imagine changes to the NSArray cluster that would allow this, but it doesn't exist in Cocoa today (and could impact NSArray performance in the normal case, making it a non-starter). Even if we had it, there's probably too much code out there that relies on the current behavior to ever allow mutability introspection to be trusted.
There's no (documented) way to determine if a string is mutable at runtime or not.
You would expect one of the following would work, but none of them work:
[[s class] isKindOfClass:[NSMutableString class]]; // always returns false
[s isMemberOfClass:[NSMutableString class]]; // always returns false
[s respondsToSelector:#selector(appendString)]; // always returns true
More info here, although it doesn't help you with the problem:
http://www.cocoabuilder.com/archive/cocoa/111173-mutability.html
If you want to check for debugging purposes the following code should work. Copy on immutable object is itself, while it's a true copy for mutable types, that's what the code is based on. Note that since it's calling copy it's slow, but should be fine for debugging. If you'd like to check for any other reasons than debugging see Rob answer (and forget about it).
BOOL isMutable(id object)
{
id copy = [object copy];
BOOL copyIsADifferentObject = (copy != object);
[copy release];
return copyIsADifferentObject;
}
Disclaimer: of course there is no guarantee that copy is equivalent with retain for immutable types. You can be sure that if isMutable returns NO then it's not mutable so the function should be probably named canBeMutable. In the real world however, it's a pretty safe assumption that immutable types (NSString,NSArray) will implement this optimization. There is a lot of code out including basic things like NSDictionary that expects fast copy from immutable types.