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

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.

Related

Line of code from Swift to 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.

Minimising function names with lengthy parameters

We are using a web service to fetch data. As project progressed, number of params being passed between functions also increased. To make it more readable and easier to add/remove parameters in future thought of using a dictionary instead. So every function calls will have only one parameter , a dictionary with all required parameters in it.
So to set a parameter I need to do [aDictionary setObject:foo forkey:#"bar"] and to get a parameter, it would be [aDictionary objectForKey:#"bar"].
To access the variables easily I thought of using a Model class with all common parameters used as properties. So for one function call say 3 out of 10 properties would be used and rest will be not be set. So it would be like paramModel.foo = #"bar".
If I would do it like this, will I be wasting memory for unused properties which are not initialised. And is this right in doing so ?
Continuing Amin Negm-Awad's points: If you are finding yourself passing along a lot of parameters to many methods, you almost certainly have incorrectly defined your model classes. Rather than creating a generic dictionary, create a simple value object that holds the related properties.
As an example, consider NSURL. You would never do this:
[self handleScheme:scheme host:host path:path];
Instead you do this:
NSURL *URL = [[NSURL alloc] initWithScheme:scheme host:host path:path];
[self handleURL:URL];
This is the correct way to consolidate parameters, and to improve your design.
Also, if you're taking a large number of boolean parameters or other kinds of "options," first consider whether you have a method that is doing too many things. Perhaps it should just be broken up into multiple methods that each works a specific way. If you really do need to pass multiple boolean options, in ObjC, this is often done with bit fields rather than with many parameters. Look at [NSString rangeOfString:options:] for an example.
No, it is strange. (Of course this is a subjective opinion.)
A. "As project progressed, number of params being passed between functions also increased."
There is only a connection between size of a software and numbers of parameters to a method (in your example there is no function): if you do something wrong in your design.
Split your code into modules, into classes, define good relationships between them and so on.
Define classes that can hold connected data.
B. I cannot see, what becomes more readable using dictionaries:
[receiver doSomethingWithA:#"a"
B:#"b"
C:#"c"];
NSMutableDictionary *aDictionary = [NSMutableDictionary new];
[aDictionary setObject:#"a" forKey:#"A"];
[aDictionary setObject:#"b" forKey:#"B"];
[aDictionary setObject:#"c" forKey:#"C"];
[receiver doSomethingWithABC:aDictionary];
It is more code, it is more complex code (because it needs an additional instance object), arguments and its "parameter destination" are wrested apart.
Inside the method you have to read out the arguments from the dictionary. This is additional boiler plate code.

methods sequence by NSMutableArray/NSMutableDictionary contents (Image multi-effecting)

What I want to do:
I want to implement ability for user to use CIFilters on image. So I need somehow to fix it's sequence. For example if user opens image, then applies CIGaussianBlur, and then CIColorControls and then CISepia, I need to get result like that:
On user opened image apply CIGaussianBlur -> on CIGaussianBlur output image apply CIColorControls - > on CIColorControls output image apply CISepia.
Thats OK. But what if then user turns off CIGaussianBlur? I need then to repeat this effect's sequence just without blur. It would look like this:
On user opened image apply CIColorControls -> on CIColorControls output image apply CISepia.
The question
Is it possible to do something like this:
After applying any effect, add some string in NSMutableArray or NSMutableDictionary. Then when applying another effect, check NSMutableArray or NSMutableDictionary contents like that:
if object at index 0 is equal to "blur", apply blur on source image, then take blur's output image like current effect's input image
And so on? So that effects would be re-applied every time in their sequence made by user.
If it is possible maybe someone could suggest me any solution?
I think that this is a great instance for the factory idea to be used.
You should store your array of filters to process the image as an array - that maintains sort order, and is fairly straightforward to deal with (other than something like a NSCountedSet).
The next logical question to ask, then, is how do we apply the factory pattern here? The most important thing to consider is what type should the context object be? Here are a few thoughts:
Using NSString as a constant identifier.
Probably the simplest to start, its , and easy to understand - the downside is that it's slower than other options, and can get to be quite the complex if-else block, as you cannot use a switch statement on a NSString.
NSNumber, wrapping an enum value.
This is probably one of the better options. You can convert right down to an int variable, which compares quite fast on almost any processor I can imagine, and, if you use ObjC 2.5's fancy literals, you could do something like this:
[filters addObject:#(filterType_gaussianBlur)];
Where filterType_gaussianBlur is an enum constant or something.
Another advantage to using an enum is the support for switch statements out of the box. It cleans up your code if done properly, it's faster than a large if-else block, the only thing to look out for is ensuring that you break properly!
Storing Class objects
This one may require some explaining. In objective-c, you can actually store a reference to the type of an object, CIGaussianBlur, NSString, NSData, etc.
This class "object" allows you to dynamically create an object based just on it's type, for example:
Class cls = nil;
if (stringMutable)
cls = [NSMutableString class];
else
cls = [NSString class];
NSString *mutableOrNot = [[cls alloc] initWithString:#"Hello World!"];
However, the disadvantage to this approach would be the inability to configure the objects after they are initialized, and you must use the same selector (method) to initialize each one. If that is not an issue (I do not use CoreImage), then using the Class approach should be fine.
All in all, use whatever makes sense in the situation. If these filters need no additional configuration after they have been initialized, then approach 3 makes a lot of sense. I personally wouldn't recommend approach 1, unless it really is necessary to use a string. Whenever you can, always try to control the values that an object can have. It makes your life much easier, trust me.

Is it possible to know an array (or arrays) which adding an object?

Follow is some code for example.
NSArray *test1 = [[NSArray alloc] initWithObjects:#"TEST", nil];
[someArray addObject:test1];
:
:
too many code lines.
:
:
At some place
NSArray *addingArray = [test1 whoisAddingOrContainingMe(?)];
I want to know a pointer of someArray as method of test1 instance.
Is there a method like this?
No, you can't "reverse lookup" the containers you are contained in.
From a design perspective this would be somewhat difficult, since conceptually there's no difference between having a reference to oneself in an "array", in any other container, or in any other object that's not considered to be a container. Thus, you have to record every single "retain" by passing it an additional "owner" parameter, and since retains and releases can be done in vastly different places you would also need to pass "owner" pointers around so that an eventual "release" can refer to the proper retain.
Or, to put it short: it would be a huge mess :-)
As suggested before, if you know what arrays can actually contain you -- and that should be much easier for your application -- you could check them. Or you could add a list to the objects to record where they have been added, probably via methods like "addTo:" and "removeFrom:".
I think you want NSArray's -containsObject: method.

How to test property existence and type based on NSString typed key?

In my quest to update a Core Data model within my iOS project, I'm querying a server for JSON objects that correspond - to some extent - with the managed entities of my model. The end result I'm striving for is a reliable update solution from JSON output.
For the examples in this question, I'll name the core data managed object existingObj and the incoming JSON deserialized dictionary updateDict. The tricky part is dealing with these facts:
Not all properties of the existingObj are present in the updateDict
Not all properties of the updateDict are available in the extistingObj.
Not all types of existingObj's properties match the JSON deserialized properties. (some strings may need a custom Objective-C wrapper).
updateDict may contain values for keys that are uninitialized (nil) in existingObj.
This means that while iterating through the updated dictionaries, there has to be some testing of properties back and forth. First I have to test whether the properties of the updateDict exist in existingObj, then I set the value using KVC, like so:
// key is an NSString, e.g. #"displayName"
if ([existingObj respondsToSelector:NSSelectorFromString(key)) {
[existingObj setValue:[updateDict objectForKey:key] forKey:key];
}
Although this part works, I don't like the fact that I'm actually testing for displayName as a getter, while I'm about to call the setDisplayName: setter (indirectly via KVC). What I'd rather to is something like [existingObj hasWritablePropertyWithName:key], but something that does this I can't find.
This makes for subquestion A: How does one test for a property setter, if you only have the property's name?
The next part is where I'd like to automate the property identification based on their types. If both the updateDict and the existingObj have an NSString for key #"displayName", setting the new value is easy. However, if the updateDict contains an NSString for key #"color" that is #"niceShadeOfGreen", I'd like to transform this into the right UIColor instance. But how do I test the type of the receiving property in existingObj so I know when to convert values and when to simply assign? I was hoping for something along the lines of typeOfSelector:
if ([existingObj typeOfSelector:sel] == [[updateDict objectForKey:key] class]) {
// regular assignment
} else {
// perform custom assignment
}
Of course this is boguscode. I can't rely on testing the type of the existingObj-property's value, for it may be unitialized or nil.
Subquestion B: How does one test for the type of a property, if you only have the property's name?
I guess that's it. I figured this must be a dupe of something that's already on here, but I couldn't find it. Maybe you guys can?
Cheers, EP.
P.S. If you'd have a better way to synchronize custom Objective-C objects to deserialized JSON objects, please do share! In the end, the result is what counts.
If you want to query whether an object has a setter for a given KVC key called key which corresponds to a declared property, you need to check whether it responds to a selector method called setKey: (starts with set, capitalise the first character in key, add a trailing colon). For instance,
NSString *key = #"displayName";
NSString *setterStr = [NSString stringWithFormat:#"set%#%#:",
[[key substringToIndex:1] capitalizedString],
[key substringFromIndex:1]];
if ([obj respondsToSelector:NSSelectorFromString(setterStr)]) {
NSLog(#"found the setter!");
[obj setValue:someValue forKey:key];
}
Two remarks:
Even though properties can have setters with names that do not follow the pattern described above, they wouldn’t be KVC compliant, so it is safe to check for set<Key>: since you’re using KVC to set the corresponding value.
KVC doesn’t use the setter method only. If it doesn’t find a setter method, it checks whether the class allows direct access to instance variables and, if so, use the instance variable to set the value. Also, if no setter method or instance variable is found, it sends -setValue:forUndefinedKey: to the receiver, whose class might have overridden the standard implementation that throws an exception. This is described in the Key-Value Coding Programming Guide.That said, if you’re always using properties, checking for the setter method should be safe.
As for your second question, it is not possible to query the runtime to know the actual Objective-C class of a property. From the runtime perspective, there’s an implementation specific type encoding for properties and general types (such as method parameters/return types). This type encoding uses a single encoding (namely #) for any Objective-C object, so the type encoding of an NSString property is the same as the type encoding of a UIColor property since they’re both Objective-C classes.
If you do need this functionality, one alternative is to process your classes and add a class method that returns a dictionary with keys and corresponding types for every property (or the ones you’re interested in) declared in that class and superclasses, or maybe some sort of description language. You’d have to do this on your own and rely on information not available during runtime.