How to initialize a class with many constructor arguments? - objective-c

I have a class that takes many arguments to create. It’s a sort of an audio processor that needs a sample rate, sample resolution, number of channels etc. Most of the parameters have sane defaults. And most of them should be only settable in the initializer (constructor), because it makes no sense to change them afterwards. I do not want to create a gargantuan initializer with all the parameters because (1) it would be huge and essentially it would only copy the passed values, doing no real work, and (2) the user would have to specify values for all the parameters. What’s a good way to solve this?
I’ve tried writing getters and setters for the params. This means that I could not create the “real” audio processing unit in the constructor, since the parameter values are not known then. I had to introduce a new method (say prepareForWork) so that the users can do something like:
AudioProcessor *box = [[AudioProcessor alloc] init];
[box setSampleRate:…];
[box setNumberOfChannels:…];
[box prepareForWork];
[box doSomeProcessing];
This is nice because it does not require an unwieldy constructor. Also the defaults are set in the initializer which means that I can take a fresh AudioProcessor instance and it could still do some work. The flip side is that (1) there is an extra method that has to be called before the instance can do any real work and (2) the class should refuse to change any of the parameters after prepareForWork was called. Guarding both these invariants would take some boilerplate code that I don’t like.
I thought I could create a special “preset” class that would look like this:
#interface SoundConfig : NSObject {
NSUInteger numberOfChannels;
NSUInteger sampleResolution;
float sampleRate;
}
And then require an instance of this class in the AudioProcessor initializer:
#interface AudioProcessor : NSObject {…}
- (id) initWithConfig: (SoundConfig*) config;
Default values would be set in the SoundConfig initializer, the AudioProcessor constructor would be simple and there would be no invariants to keep watching by hand.
Another approach I thought of was a kind of AudioProcessorBuilder class. You would create an instance of that, set the audio params through accessors and then finally it would build an AudioProcessor instance for you, setting all the properties through a non-public setters so that you could not change them later (and break the invariant).
Now that I write this I favour the SoundConfig approach. How do you solve this, is there a better approach?

See how NSURLConnection is implemented and used. It uses an NSURLRequest object to parameterise it, similarly to the way your SoundConfig object parameterises the AudioProcessor object.

The usual way is indeed to create a gargantuan initializer together with several initializers for non default values or sets of values.
-initWithSampleRate:numberOfChannels:sampleResolution:
-initWithSampleRate:sampleResolution:
-initWithSampleRate:numberOfChannels:
-initWithNumberOfChannels:sampleResolution:
-initWithNumberOfChannels:
-initWithSampleResolution:
-initWithSampleRate:
-init
But the SoundConfig approach looks simpler.

Usually, when you have class with many constructor parameters, especially when some or most of them are optional, you want to use Builder Pattern. Funny thing, I cannot find examples for objective-c, so I am not sure if it could be easily applied here...

Related

Objective-C: Use singleton vs. use class as an object?

I've been wondering in what cases it is really necessary to adopt the singleton pattern in objective-C (e.g., define a dedicated class and create a single instance), that using the class as an object won't do.
Particularly, I'm thinking of the following solution:
Define and use appropriate class methods, instead of instance methods on the singleton instance;
Use static variables (file-scope globals), instead of instance variables of the singleton instance;
Use the class object when registering as an observer for notifications, instead of the singleton instance. Although the class object is an objective-C object in its own right (right?), this would require that the notification handler registered be a class method; (is this possible?)
For example, instead of having a Texture class (model object) and a TextureManager singleton (resource manager), you could have all texture creation/cleanup implemented as class methods and static variables of the same Texture class (factory pattern plus some resource management).
Any thoughts on this design?
EDIT:
Now that I think of it, and still in the Texture example above, even if I keep the two classes separate (Texture and TextureManager) I must choose between A. Having the manager be a singleton, and operate it with instance methods, or B. Having the manager be an instanceless, auxiliary class. To clarify:
Texture* myTexture = [[TextureManager defaultManager] textureWithName:#"TextureName"];
// (singleton, client uses instance methods)
versus
Texture* myTexture = [TextureManager textureWithName:#"TextureName"];
// (Class standing in for singleton, client uses class methods)
The latter looks more straightforward and less cumbersome/verbose, but I wonder which design is "more correct". Of course, the former allows for more than one TextureManager instance shall the need arise (not in my case).
I have been thinking about the same thing and I think I have an answer for you.
It depends on what you need to do with it. Neither is necessarily more "correct".
Read on if you want the details of how I came to my conclusion or scroll down to the tl;dr section.
As you said, it would appear (externally) less cumbersome to access the singleton to have the class manage the singleton for you. Essentially you would do this by replacing the singleton's factory method with an initializer method. Looking at Apple's documentation on this you can see where they show a "shared" method that acts as the factory to produce the singleton upon demand.
static MyGizmoClass *sharedGizmoManager = nil;
+ (MyGizmoClass*)sharedManager
{
if (sharedGizmoManager == nil) {
sharedGizmoManager = [[super allocWithZone:NULL] init];
}
return sharedGizmoManager;
}
Instead of doing this you could replace the method with a void initializer like so:
+ (void)initializeMyGizmo
{
if (sharedGizmoManager == nil) {
sharedGizmoManager = [[super allocWithZone:NULL] init];
}
// whatever else needs to be done to the singleton to initialize it
}
and then ONLY ever use class methods and allow the MyGizmoClass to manage updates to the singleton like [MyGizmoClass setGizmoName:#"Gadget"].
NOTE: In this scenario it would be confusing to someone looking at the .h file to see properties, in which case they may come to the conclusion that they should create an instance of the object themselves, or be able to have access to the singleton in some form or fashion. So if you were to go the route of encapsulating access to the singleton it would not be wise to use public variables.
To that point:
If you do limit access to solely through the class itself you lose any getters and setters or other free things that come along with properties. This means that if MyGizmoClass were to have as part of it's model an NSString *gizmoName you would be forced to create custom getters and setters for this "property" and keep it either as an ivar or property in an interface extension in the .m file (i.e. private) of the singleton class, or as an adjacent static variable.
So this begs the question (and is what got me pondering in the first place), should we even include the line static MyGizmoClass *sharedGizmoManager = nil; at all or can we nix the internal interface extension altogether and replace any possible ivars or properties that we want to limit access to with static implementations in the implementation?
I answered that already...
It depends on what you need to do with it.
tl;dr
First Scenario
If you ever (even the slightest chance) need to subclass your
TextureManager or could create multiple instances of it (making it
no longer a singleton) it would be better to stick to the regular
Apple convention for a singleton.
This includes multiple "singletons" wherein you might have several
TextureManagers preconfigured with different settings.
In this case you would use properties as you need them (publicly or
privately) as well as ivars. You could also use a mix of ivars and
statics but you would still always need to have a static instance of
your TextureManager inside of the TextureManager implementation.
Second Scenario
If you ONLY will ever need ONE instance of the TextureManager and it will run completely standalone with no intermixing further down the line then you could completely remove the static instance of your class within the implementation in the .m file and replace ivars and properties with static variables within that implementation.
This can be useful if you are storing off properties or settings in CoreData and only need them for configuration.
Just remember in this case you will have to create all getters and setters for the static variables and will only be able to access them using class methods (but that's sorta the point).
Other Interesting Stuff
This answer offers an interesting solution to the question of when and how to call the "initializer" method or create the singleton. This can be used with each scenario to either initialize the singleton in the first scenario, or preload defaults into the class-level statics in the second scenario.
If you want to stick with a static singleton in the implementation you might look at this article to give you a better idea at the true "global scope" of your singleton.
Yes you can definitely make a Texture class without needing a singleton.
Singletons probably should not be created and used as an object.
Singletons can be used for many important things.
I certainly don't know all of the things they can be used for, but i will tell you what i have used them for in the past.
I usually use singletons for level navigation in a game with many levels (like Angry Birds).
By level navigation, i mean... when a player completes a certain level in a game i simply call a class method on the singleton and pass in the level number, then the singleton's class method figures out which level is next (if user presses 'next level' button).
I can help you understand the Singleton class better and when it applies.
Pattern : Singleton
Intent : Enforce that a class can only have a single instance, as well as making that instance accessible to any other object.
Motivation : Sometimes we need to make sure that there exists only a single object of a certain type in our problem domain. Example: A student carries around only a single backpack, which he can fill with books. We would not want to relate him to secondary backpack, with even more books.
Use when :
There is need for only a single instance of a class, and that instance must be accessible from different objects within your code.
When you (possibly) need to be able to add more functionality to that class by subclassing it.

Dynamic Getters and Setters with Objective C

I am in a situation where I want to dynamically generate getters and setters for a class at runtime (in a similar manner to what NSManagedObject does behind the scenes). From my understanding, this is possible using resolveInstanceMethod: on a specific class. At this point, you would have to use class_addMethod to dynamically add the method based on the selector. I understand this at a theoretical level, but I haven't delved much into the obj-c runtime, so I was curious if there were any great examples of how to do this. Most of my knowledge comes from this article:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html
Any thoughts / examples?
The only nice discussion I know is at Mike Ash's blog post. It's not that hard, actually.
I once needed to split a big NSManagedObject subclass into two, but decided to keep the fact an implementation detail so that I don't have to rewrite other parts of my app. So, I needed to synthesize getter and setter which sends [self foo] to [self.data foo], automatically.
To achieve that, I did the following:
Prepare the new method, already in my class.
- (id)_getter_
{
return objc_msgSend(self.data, _cmd);
}
- (void)_setter_:(id)value
{
objc_msgSend(self.data, _cmd,value);
}
Note that _cmd has the selector in it. So, usually, _cmd is either #selector(_getter_) or #selector(_setter_) in these methods, but I'm going to plug the implementation of _getter_ as the implementation of foo. Then, _cmd contains #selector(foo), and thus calls self.data's foo.
Write a generic synthesizing method:
+(void)synthesizeForwarder:(NSString*)getterName
{
NSString*setterName=[NSString stringWithFormat:#"set%#%#:",
[[getterName substringToIndex:1] uppercaseString],[getterName substringFromIndex:1]];
Method getter=class_getInstanceMethod(self, #selector(_getter_));
class_addMethod(self, NSSelectorFromString(getterName),
method_getImplementation(getter), method_getTypeEncoding(getter));
Method setter=class_getInstanceMethod(self, #selector(_setter_:));
class_addMethod(self, NSSelectorFromString(setterName),
method_getImplementation(setter), method_getTypeEncoding(setter));
}
Note that this is a class method. So self stands for the class. Note also that I didn't hardcode type encodings (which tells Objective-C runtime what the arguments of the particular method are). The syntax of type encodings is documented, but constructing by hand is very error-prone; I wasted a few days that way until Mike Ash told me to stop it. Generate it using an existing method.
Generate forwarders at the earliest possible time:
+(void)load
{
for(NSString*selectorName in [NSArray arrayWithObjects:#"foo", #"bar", #"baz",nil]){
[self synthesizeForwarder:selectorName];
}
}
This generates foo, setFoo:, bar, setBar:, and baz, setBaz:.
Hope this helps!
Another example is one I wrote, called DynamicStorage, available here:
https://github.com/davedelong/Demos
The primary impetus behind it was this question, which was asking how to use an NSMutableDictionary as the backing store for any object ivar. I wrote a class that will generate getters and setters for any #property, respecting things like a custom getter/setter name, the object memory management policy, etc. The neat thing about it is that it's using imp_implementationWithBlock() so that it only has to calculate the appropriate property name once (and then captures and saves it as part of the block).

Objective C - preferred way to create and initialize an object

Is one of these two ways to create and initialize an object preferable?
MyClass oClass = [[MyClass alloc] init];
oClass.length = 5;
oClass.text = #"Hello";
or using a class method that contains about the same code but looks like this:
MyClass oClass = [MyClass myClassWithLength:(int) 5 andText:(NSString *) #"Hello"];
I hate it when I see things done more than one way and I have no idea if one is better than the other, or why!
Don't be a hater. :-)
By the way, I'm assuming you meant:
(Edit: removed unnecessary casts)
MyClass oClass = [[MyClass alloc] initWithLength:5 andText:#"Hello"];
The reason for multiple init... methods is to make it more convenient for developers to create properly initialized instances. So, for example, if you find that developers often need to create instances of MyClass with a length and text, you make their life easier by providing an API that allows them to do that in one step. And if you find that developers also frequently need to create instances of MyClass with just a text string, you might also provide an -initWithText: method.
And if the instances created this way are frequently used as temporary objects (i.e., not stored in instance variables or static variables), you might also add a class convenience method like +myClassWithText: that returns an autoreleased instance of MyClass initialized with the provided text string.
As to which one is better: it's always better to fully initialize an object when possible, so if the object needs both values to be properly initialized, use the method that allows you to provide both arguments. And if you don't need to store a reference to the instance you're creating, use the class convenience method so your code doesn't have to deal with memory management.
If the object is unusable without the length and text, then the second option might be better. If those fields are optional, then the first one is better.
However, I don't think there is absolute truth to this question.
If you have a class with many properties it's very unlikely to initialize them all in one single line of code. Both ways work fine for me.
If an initWithSomething: method is available and you want to provide initial values for those properties, I would always prefer it just because it's simpler. It also will always work even with immutable versions of a class.
But neither init method is inherently "better." Classes usually have one or two designated initializers and all the others just call those with default values — it doesn't necessarily leave the instance's properties untouched. The documentation for a class should indicate what its initializers do and which is the designated initializer for the class. For example, [[NSDate alloc] init] uses NSDate's designated initializer, initWithTimeIntervalSinceReferenceDate:, to create a date object representing the current date and time.
Incidentally, this also means that when you're subclassing a class, you only need to override its designated initializer. Since the others just call that, they get your new behavior for free.

Can I override how #synthesize works in Objective C?

I'm creating a base class that has an isDirty flag. It is set any time one of its properties changes, but since it's a base class, it doesn't know what its properties are. So basically, on every subclass, I have to override every - set: method to something like this:
- (id) setName:(NSString *)value {
if ([name isEqualToString:value]) {
return;
}
[name autorelease];
name = [value retain];
isDirty = YES; //Here's the important bit
}
Almost every line of that is what the automatically-synthesized setter would do. Is there any way I can override what #synthesize actually creates?
There are other options I have come up with, but they all seem like they would be much slower at runtime than this method. I've thought of things like adding an object to observe its own property changes, or creating a generic function to do all that and just pass in the address to the iVar and the new value, but that still requires overriding the setter.
Any ideas? If it makes a difference, it's for an iPhone app.
Several issues here:
(1) If you are concerned about setter performance, you shouldn't be using -isEqualToString: in your setter. Do a pointer compare instead because that is all that matters in this context.
(2) If you have an NSString attribute, you should be copying on set. Copy is free for immutable strings and will save your bacon for mutable strings (by preventing the caller from mutating the string out from under you).
(3) Again with performance; you checked for equality, but then use autorelease. That incurs unnecessary overhead.
(4) * they all seem like they would be much slower at runtime* indicates that you haven't actually tried it, haven't identified a performance problem, and are prematurely optimizing your code. Given (1) and (3), there is likely much more easily addressed performance issues.
My suggestions:
(1) Use #synthesize. It will generate correct and fast code, addressing (1) and (3).
(2) Use KVO or one of the other mechanisms. Until you identify a performance problem through instrumentation and quantification, you don't have a performance problem.
(3) Consider using CoreData (unless, of course, you are targeting OS 2.x). The example code is from something that is obviously a model object. If your code is nicely factored into model/view/controller, using CoreData at the model layer can both simplify your application and CoreData does a wonderful job of change tracking.
There's no way I know of that enables you to override what #synthesize does.
At the end of the day, it's used for creating basic accessor methods - ie. those that don't have specific behaviour.
Maybe you should look into Key Value Coding and Key Value Observing?
There isn't.
What you want to achieve is only possible by digging deep into the Objective-C runtime or by using proxy objects.
Why don't you have a look at KVO again?
If you write your own accessor method(s) #synthesize respects that. #synthesize gives precedence to accessors you write on your own. Just provide the accessor you like and #synthesize will be ignored on that one. For example you could implement an accessor that creates the property only in case it isn't already there.
Example:
#synthesize standardUserDefaults;
- (NSUserDefaults *)standardUserDefaults {
NSLog(#"standardUserDefaults");
if (!standardUserDefaults) {
NSLog(#"standardUserDefaults new");
self.standardUserDefaults = [NSUserDefaults standardUserDefaults];
}
return standardUserDefaults;
}
Here the "setter" is synthesized while the "getter" is not.

How to inherit from NSDictionary?

I have an object called Settings that inherits from NSMutableDictionary. When I try to initialize this object using
Settings *settings = [[Settings alloc] initWithContentsOfFile: #"someFile"]
it returns an object of type NSCFDictionary. As a result, it doesn't recognize my additional methods. For example, when I call the selector "save", it objects:
[NSCFDictionary save]: unrecognized selector sent to instance 0x524bc0
Of course, it's OK when I initialize using the garden variety
Settings *settings = [[Settings alloc] init]
I tried to cast it again to Settings but that didn't work. This seems really simple - what am I missing?
Thanks
NSDictionary is a class cluster. This means that the value returned from its init methods is not strictly an NSDictionary, but a subclass that implements the actual functionality. In almost every case, it is better to give your class an NSDictionary as an instance variable or to simply define a category on NSDictionary.
Chuck is correct about NSDictionary (and Dave, by extension, about NSArray/Set/String) and class clusters. Odds are that -[NSDictionary initWithContentsOfFile:] calls down to a different initializer than -init does, which is why it swaps out your allocated Settings instance for another subclass of NSMutableDictionary. (The initialization action when reading from a file may select a particular known subclass of NSDictionary which performs well for loading from a file, etc.)
I'll echo Chuck's guidance that it is almost always better to use composition or categories than inheritance for an NSDictionary. It's highly likely that you could accomplish what you're doing with categories in a much simpler way, and expose yourself to fewer potential bugs in the process. Consider yourself warned before deciding to subclass.
That being said, both NSDictionary and NSMutableDictionary have been designed to support subclassing, and on rare occasions that's the right thing to do. Think long and hard about it before trying it. If you find it's the right choice for your design, here are some key points to know and do as needed:
Override the following primitive methods from NSDictionary:
-count
-objectForKey:
-keyEnumerator
-initWithObjects:forKeys:count: (designated initializer)
Override the following primitive methods from NSMutableDictionary:
-setObject:forKey:
-removeObjectForKey:
If you're supporting NSCoding, be aware of classForKeyedArchiver and replacementObjectForKeyedArchiver: (both instance methods from NSObject) — they can totally change how your class responds, and you often unintentionally inherit some odd behavior from NS(Mutable)Dictionary. (You can verify if they are the culprit by setting a breakpoint on them, or implementing them to call super and breaking on your own code.)
I've implemented a number of these points in an NSMutableDictionary subclass of my own. You can check it out and use the code however may be helpful to you. One that particularly helped me (and could be the solution for your problem) was overloading the designated initializer, which is currently undocumented (Radar #7046209).
The thing to remember is that even though these bullets cover most common uses, there are always edge cases and less common functionality to account for. For example, -isEqual: and -hash for testing equality, etc.
If you actually read the spec for NSDictionary (a rash action, I know) you'll find a section named "Subclassing Notes". In it you will read:
If you do need to subclass NSDictionary, you need to take into account
that is represented by a Class cluster—there are therefore several
primitive methods upon which the methods are conceptually based:
initWithObjects:forKeys:
count
objectForKey:
keyEnumerator
In a subclass, you must override all these methods.
From https://stackoverflow.com/a/1191351/467588, this is what I did to make a subclass of NSDictionary works. I just declare an NSDictionary as an instance variable of my class and add some more required methods. I don't know what to call them though.
I posted my code sample here https://stackoverflow.com/a/10993594/467588.
This question is very old, and since most of these answers were posted, Apple has introduced object subscripting, which allows you to make your own classes behave more like NSMutableArray or NSMutableDictionary. This is simpler than the alternatives discussed above.
At a minimum, you have to override these methods:
//Array-style
- (id)objectAtIndexedSubscript:(NSUInteger)idx;
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx;
//Dictionary-style
- (id)objectForKeyedSubscript:(id <NSCopying>)key;
- (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key;
Here's a nice tutorial on how to do just that.