Minimising function names with lengthy parameters - objective-c

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.

Related

Why do objective-c array parameters not use colon notation?

Im currently learning some objective-c from the big ranch guide book. My understanding is that methods with multiple parameters use colons to separate each parameter, but when reading about creating arrays, i found this snippet of code:
NSArray *dateList = [NSArray arrayWithObjects:now, tomorrow, yesterday, nil];
This has left me confused as i thought objective-c method parameters must each be preceded by a portion of the method name along with a colon. Can anybody explain this to me?
This is an exception to the rule; this is commonly called a variadic method. If you look at the definition in NSArray.h:
+ (instancetype)arrayWithObjects:(id)firstObj, ... NS_REQUIRES_NIL_TERMINATION;
you see that you can specify an arbitrary number of parameters, as long as the last one is nil (this is called the sentinel).
This saves the developers from creating a large number of different methods having roughly the same functionality, each of which accept a different number of parameters. They did so in NSObject, where you have
- (id)performSelector:(SEL)aSelector withObject:(id)object1;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
(but no further methods).
The method only has one parameter, a variable parameter list.
Here is the Objective-C declaration from the Apple Developer website:
+ (instancetype nonnull)arrayWithObjects:(ObjectType nonnull)firstObj, ...;
There's no need for colon separation, because the object list is treated as one parameter, even thought it looks like many parameters!

Bundle declarations into one statement or not?

Given the following Objective-C example, is it simply a matter of style and ease of reading to keep separate statements or to bundle them into one? Are there any actual benefits of either? Is it a waste of memory to declare individual variables?
NSDictionary *theDict = [anObject methodToCreateDictionary];
NSArray *theValues = [theDict allValues];
NSString *theResult = [theArray componentsJoinedByString:#" "];
or
NSString *theResult = [[[anObject methodToCreateDictionary] theValues] componentsJoinedByString:#" "];
I take the following into consideration when I declare a separate variable:
If I might want to see its value in the debugger.
If I am accessing the variable more than once.
If the line is too long.
There is no practical difference between the two approaches, however.
Also, you haven't asked directly about this, but be aware, when you access objects using dot notation, for example:
myObject.myObjectProperty1.myObjectProperty1Property;
If you are going to access myObjectProperty1Property more than once, it can be advisable to assign it to a local named variable. If you don't, the look-up will be executed more than once.
Now I can't emphasise enough, for many if not most situations this time saving is so infinitesimal as to seriously call into question whether it is worth even spending the time doing extra typing for the assignation! So why am I raising this? Because having said that - stylistic "anality" apart (I just made up a new word) - if the section of code you are writing is running in a tight loop, it can be worth taking the extra care. An example would be when writing the code which populates the cells in a UICollectionView that contains a large number of cells. Additionally, if you are using Core Data and you are using the dot notation to refer to the properties of NSManagedObject properties, then there is far greater overhead with each and every look-up, in which case it is much more surely worth taking the time to assign any values referred to by "nested" dot notation calls to a local variable first.

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.

Using sortUsingSelector on an NSMutableArray

I have used sortUsingSelector to sort an NSMutableArray of custom objects.
Now I'm trying to sort an NSMutableArray containing NSMutableArrays of custom objects.
Can you use sortUsingSelector on an NSMutableArray, or does it only work for custom classes?
If you can use blocks, the most straightforward way using sortUsingComparator:. Otherwise, you'll need to use sortUsingFunction:.
In either case, you are going to need to write a custom block or function that takes two arrays as arguments and returns a sort order based on their contents (I'm not sure what logic you are using to determine if array A or array B is "before" or "after" the other).
You'd do something like:
static NSInteger MySorterFunc(id leftArray, id rightArray, void *context) {
... return ascending/descending/same based on leftArray vs. rightArray ...
}
Then:
[myArrayOfArrays sortUsingFunction: MySorterFunc context: NULL];
It sends the selector to the objects, so you'll need to use one of the other sorters. Probably sortUsingFunction:context:.
Of course you can also use sortUsingSelector:, it really doesn’t matter whats the object in your array as long as it responds to the selector you want to use. But NSMutableArray and NSArray don’t have any comparison methods themselves, so you’d have to extend them using a category to implement your compare method.
So you probably want to use the other sorting methods pointed out in the other answers here. It’s not impossible to use sortUsingSelector: but it is rather inconvenient and most people (including me) would argue that it’s bad style to write a category for that.

Use of pass by reference in Objective-C

Looking at the JSON-Framework source, it makes heavy use of pass by reference in many of the parser method signatures. i.e.
#interface SBJsonParser ()
- (BOOL)scanValue:(NSObject **)o;
- (BOOL)scanRestOfArray:(NSMutableArray **)o;
- (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o;
#end
This ends up being used something like this:
id o;
[self scanValue:&o];
// Do something with o
- (BOOL)scanValue:(NSObject **)o {
// Cut down for brevity
return [self scanRestOfDictionary:(NSMutableDictionary **)o];
}
- (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o {
// Cut down for brevity
*o = [NSMutableDictionary dictionaryWithCapacity:7];
[*o setObject:#"value" forKey:#"key"];
return YES;
}
What are the benefits to this approach?
EDIT: I'm asking more from a design point of view. I understand what pass by reference is, I'm just wondering when it's appropriate to use it. The design used in SBJsonParser is similar to the API used in NSScanner:
- (BOOL)scanUpToString:(NSString *)stopString intoString:(NSString **)stringValue;
To me, this implies that the string which was scanned is secondary to needing to know if something was scanned. This is in contrast to the API used by NSString:
+ (id)stringWithContentsOfFile:(NSString *)path encoding:(NSStringEncoding)enc error:(NSError **)error;
In that API, the contents of the file is the primary concern, and the NSError reference is used to pass back an error in the event that something goes wrong.
Just after some general thoughts on which API is most appropriate, when.
Those are "output" parameters. They allow the called method to assign a value to your local variable "o". In other words, you're not passing in a reference to an object, but a reference to a local variable.
In your case, the methods return a BOOL to indicate success or failure; therefore, they use output parameters to return other values and objects.
It's really just a style question. It should be consistent across an entire API.
On the one hand, you've got a style where the status code of the call is always returned and output of the call is in the parameter list.
Benefits? You can always check the call result for success. You can easily have multiple return values without changing the style.
Drawbacks? Can't just drop in calls in place of parameters. Harder to chain.
On the other hand, you've got a style where the primary data is returned from the call and any error codes are done through out parameters.
The benefits and drawbacks are essentially inverted.
To be fair, there's a third style: no results are passed out or returned. Instead, exceptions are used.
Benefits? Cleaner looking code.
Drawbacks? Works well for errors, but not so well for status codes that may go along with valid return codes.