How to implement a myclassWith... method in Objective-C? - objective-c

What's the best way to implement a method that returns an autoreleased object? Does the following code work correctly?
#implementation MyClass
-(void) myclassWithSomeParameter:(SomeType) parameter
{
return [[MyClass allocWithSomeParameter:parameter] autorelease];
}

The return type must be MyClass *, you need to alloc the new instance, and it should be a class method rather than an instance method (otherwise you need an existing instance of MyClass).
+ (MyClass *)myClassWithSomeParameter:(SomeType)parameter {
return [[[MyClass alloc] initWithSomeParameter:parameter] autorelease];
}
Then create instances like so:
MyClass *instance = [MyClass myClassWithSomeParameter:parameter];

Related

Objective-C return instances of different classes at init

Is it possible at Objective C at init method to return an instance of different classes?
I'm having a Class called: MyCustomClass. I also have two other different classes called Class 1 and Class2. What I'm trying to implement is: When I call [[MyCustomClass alloc] initWithSomeParameters to create instance of Class1 or Class2 depending on some condition.
MyCustomClass.m:
#import "MyCustomClass.h"
#import "Class1.h"
#import "Class2.h"
-(id) initWithSomeParameters: (id) params{
id myClass;
if (someCondition){
myClass = [[Class1 alloc] initWithSomeParameters:(id) params];
[myClass setSomething:something];
}else{
myClass = [[Class2 alloc] initWithSomeParameters:(id) params];
[myClass setSomething:something];
}
return myClass;
}
...and later I call
id myCustomClass = [[MyCustomClass alloc] initWithSomeParameters:(id) params];
Is this a wrong approach? If so, what would be the correct one?
Several others have mentioned this, but the result of calling [[MyClass alloc] init] must always be nil or a kind of MyClass. It doesn't have to specifically be an instance of MyClass; one of its descendants is possible, as with NSArray or NSString. In code, this requirement would look like:
MyClass *a = [[MyClass alloc] init];
NSAssert((a==nil) || [a isKindOfClass:[MyClass class]], #"This must always hold true.");
I've never attempted to implement this, but it would probably have to look something like this:
- (id)initAsSubclass:(NSString *)sublcassName
{
Class c = NSClassFromString(subclassName);
self = [[c alloc] init];
if (self) {
// Do Custom Init Here
}
return self;
}
The keys would be:
DO NOT perform [super init].
Create a completely new object with +alloc.
Assign the newly created object to self.
If not using ARC, perform [self autorelease], before replacing the value. (If the object that is currently executing code becomes deallocated, it can cause issues. -autorelease will defer that until this section is complete.)
You should make some kind of controller, which initializes correct classes. You can also achieve same that using class methods.
ANd in genreal this given implementation is bad, because you alloc memory once [MyCustomClass alloc] and then in -(id)initWithSomeParameters:(id)params you are allocating memory again. So, even different address will be retruned, that isn't agains apple guidelines, some apple classes also have such behavior, but they do it because of optimizations. But here it is wrong.
Its not a good approach. Its better use some helper class or us factory pattern and provide parameters to method. Then depending on parameters create an object of class and return.
Its not good approach to create object of different class in init method of different class.
Edit:
if You want to show UIView or UIAlertView depending on iOS version do like this.
#interface AlertHelper : NSObject
+ (id)getAlert;
#end
///
#implementation AlertHelper
+(id)getAlert{
NSString *version = [[UIDevice currentDevice] systemVersion];
int ver = [version intValue];
if (ver < 7){
//For iOS 6
return something;
}
else{
//for ios 7
return something
}
}
#end
The way to do it is like this:
Create Base class like:
#import "Base.h"
#import "Class1.h"
#import "Class2.h"
#implementation Base
+ (id)classWithParams:(id)params
{
id retVal = nil;
if (condition_based_on_params_means_creating_class1)
{
retVal = [[Class1 alloc] initWithSomeParameters:params];
}
else
{
retVal = [[Class2 alloc] initWithSomeParameters:params]
}
return retVal;
}
#end
Class1 inherits from Base:
#interface Class1 : Base
{
}
- (id)initWithSomeParameters:(id)parameters;
#end
Class2 inherits from Base:
#interface Class2 : Base
{
}
- (id)initWithSomeParameters:(id)parameters;
#end
Ultimately you will have:
Base* a = [Base classWithParams:yourParams];

Initialization methods

i have a MyObject. when my program runs, i create a new MyObject
self.myObject = [[MyObject alloc] initWithStuff:stuff];
later in my code, i need to create a new MyObject.
my question is, do i need to create a new MyObject with an "init" method?
.h
#import <UIKit/UIKit.h>
#interface MyObject : NSObject
{}
-(id)initWithStuff:(NSString *)stuff;
-(id)initWithNewStuff:(NSString *)newStuff;
-(id)newObjectWithStuff:(NSString *)newStuff;
#end
.m
-(id)initWithStuff:(NSString *)stuff;
{
if (self = [super init])
{
self.myStuff = stuff;
}
return self;
}
-(id)initWithNewStuff:(NSString *)newStuff;{
if (self = [super init])
{
self.myStuff = newStuff;
}
return self;
}
-(id)newObjectWithStuff:(NSString *)newStuff;
{
self.myStuff = newStuff;
return self;
}
or can i use a non-init method to create it?
in my code:
self.myObject = [[MyObject alloc] initWithNewStuff:newStuff];
or
self.myObject = [self.myObject newObjectWithStuff:newStuff];
i guess my question boils down to: what does
if (self = [super init])
do?
working with other objects such as dictionaries, i know "NSDictionary *myDict = myOtherDict" is perfect valid.
You can name your custom initializers as you want, but there's a convention to start your initializer method with "init".
In examples you wrote, the objects are a subclass of NSObject the the root class of all hierarchies. The keyword super refers to the class above in the hierarchy (your class's superclass), so basically, you're calling the init method of NSObject which creates and initializes an object right after memory has been allocated for it (that's what alloc method does). Then, you check if the method returned an object and initialize your own properties.
Take a look at this guide and make sure you understand everything what is in there https://developer.apple.com/library/mac/#documentation/cocoa/conceptual/objectivec/introduction/introobjectivec.html .
When you are calling
self.myObject = [self.myObject newObjectWithStuff:newStuff];
you just making reference on an existing memory location. If you really want a new object You should call like
self.myObject = [[MyObject alloc] initWithNewStuff:newStuff];
The alloc key word allocates memory for a variable

How to write an Objective-C convenience constructor

I'm trying to add a convenience constructor to my custom object.
Similar to [NSArray arrayWithArray:]
I know it involves a class method that returns an auto released object. I've been googling around but all I can seem to find is the definition of a convenience constructor but not how to write one.
Let's say you have the following:
#class PotatoPeeler : NSObject
- (instancetype)initWithWidget: (Widget *)w;
#end
Then to add a factory method, you'd change it to this:
#class PotatoPeeler : NSObject
+ (instancetype)potatoPeelerWithWidget: (Widget *)w;
- (instancetype)initWithWidget: (Widget *)w;
#end
And your implementation would simply be:
+ (instancetype)potatoPeelerWithWidget: (Widget *)w {
return [[[self alloc] initWithWidget: w] autorelease];
}
Edit: replaced id with instancetype. They are functionally identical, but the latter provides better hints to the compiler about the method's return type.
Generally my approach is the following: first I create a normal initializer method (instance method), then I create a class method that calls the normal initializer. It seems to me Apple uses the same approach most of the time. An example:
#implementation SomeObject
#synthesize string = _string; // assuming there's an 'string' property in the header
- (id)initWithString:(NSString *)string
{
self = [super init];
if (self)
{
self.string = string;
}
return self;
}
+ (SomeObject *)someObjectWithString:(NSString *)string
{
return [[[SomeObject alloc] initWithString:string] autorelease];
}
- (void)dealloc
{
self.string = nil;
[super dealloc];
}
#end

Objective-C Proper way to create class with only one instance

I am trying to implement a class, that subclasses NSObject directly, that can only have one instance available throughout the entire time the application using it is running.
Currently I have this approach:
// MyClass.h
#interface MyClass : NSObject
+(MyClass *) instance;
#end
And the implementation:
// MyClass.m
// static instance of MyClass
static MyClass *s_instance;
#implementation MyClass
-(id) init
{
[self dealloc];
[NSException raise:#"No instances allowed of type MyClass" format:#"Cannot create instance of MyClass. Use the static instance method instead."];
return nil;
}
-(id) initInstance
{
return [super init];
}
+(MyClass *) instance {
if (s_instance == nil)
{
s_instance = [[DefaultLiteralComparator alloc] initInstance];
}
return s_instance;
}
#end
Is this the proper way to accomplish such a task?
Thanks
You need to do a little more than that. This describes how an objective-c singleton should be implemented: Objective-C Singleton
In your scenario, there is still a way to create a second instance of your class:
MyClass *secondInstance = [[MyClass alloc] initInstance]; //we have another instance!
What you want is to override your class's +(id)alloc method:
+(id)alloc{
#synchronized(self){
NSAssert(s_instance == nil, #"Attempted to allocate a second instance of singleton(MyClass)");
s_instance = [super alloc];
return s_instance;
}
return nil;
}

custom class = custom +alloc , custom +init

I'm new with objective c for the iphone.
I'm writing a custom class, then, should I write my own +alloc, +init methods?
I believe that: the +alloc will just call [thing alloc]; and the +init will perform something like: [thing setValue:X];
is there a "default" +alloc and +init methods?
if yes, what should I wait for the default +alloc and +init?, let's say i have a NSMutableDictionary*
i.e.
#interface class1 : NSObject {
NSString *test;
NSMutableDictionary *map;
}
thanks
You generally don't need to write your own +alloc method.
For your example, you might have an -init that looks like:
- (id)init {
self = [super init];
if (self) {
map = [[NSMutableDictionary dictionary] retain];
}
return self;
}
Note that you first call the superclass -init, and check that it worked, before initializing your own variables.
You should NEVER override alloc.
As for init, which is an instance method, by the way, yes that would be the place where you'd probably want to set up your variables.