Don't let use -(id)init; method - objective-c

I'm developing an app for iPhone 3.1.3.
I have the following class:
#interface Pattern : NSObject {
NSMutableArray* shapes;
NSMutableArray* locations;
CGSize bounds;
}
#property (nonatomic, retain, readonly) NSMutableArray* shapes;
#property (nonatomic, retain, readonly) NSMutableArray* locations;
- (id) initWithNumShapes:(int)numShapes screenSize:(CGSize)screenSize;
- (void) addObject:(Object2D*) newObject;
#end
I don't want to let programmers use -(id)init; because I need to setup my fields (shape, locations, bounds) on every initialization.
I don't want to let programmers use this:
Pattern* myPattern = [[Pattern alloc] init];
I know how to implement:
- (id) initWithNumShapes:(int)numShapes screenSize:(CGSize) screenSize{
if (self = [super init]) {
shapes = [NSMutableArray arrayWithCapacity:numShapes];
locations = [NSMutableArray arrayWithCapacity:numShapes];
bounds = screenSize;
}
return (self);
}
How can I do that?

raise an exception if somebody uses the plain init
- (id)init {
[NSException raise:#"MBMethodNotSupportedException" format:#"\"- (id)init\" is not supported. Please use the designated initializer \"- (id)initWithNumShapes:screenSize:\""];
return nil;
}

You can override the init function and give default values from it if you have:
- (id)init {
return [self initWith....];
}
If you don't want init at all, still override and throw some kind of exception saying not to use init.
- (id)init {
NSAssert(NO, #"Please use other method ....");
return nil;
}
This will always give an exception if anyone tried to call init.
I would suggest to use the former case though, and have some default values.

Its always the same schema. Just call init on your superclass (NSObject).
- (id) initWithNumShapes:(int)numShapes screenSize:(CGSize)screenSize {
if(self == [super init]) {
// Custom Init your properties
myNumShapes = numShapes;
myScreenSize = screenSize;
}
return self;
}

Related

Subclassing and "promote" objects

I have a classes:
BasicObject : NSObject
AdvObject : BasicObject
in other class i make an instance by:
BasicObject *bObj = [[BasicObject alloc] initWithSomething:propertyOne andSomethingElse:propertyTwo];
BasicObject have two properties:
#interface BasicObject : NSObject
-(id)initWithSomething:propertyOne andSomethingElse:propertyTwo;
#property (strong,nonatomic) NSString* propertyOne;
#property (strong,nonatomic) NSArray* propertyTwo;
And then in initializer:
-(id)initWithSomething:propertyOne andSomethingElse:propertyTwo
{
if (self = [super init])
{
_propertyOne = propertyOne;
_propertyTwo = propertyTwo;
if(!propertyTwo) //this is not valid condition i know, not important here
{
AdvObject *aObj = [[AdvObject alloc] initWithBasic:self]; //here it what i'm more concern about
return aObj;
}
}
return self;
}
So there in AdvObject class in initializer i have:
#implementation AdvObject
#synthesize basics = _basics;
-(id)initWithBasic:(BasicObject *)bObj
{
if(self = [super init]) {
_basics = bObj;
}
return self;
}
And after that when i return this object of course i have a object.basics filled properly, but why i can't access object.propertyOne? (this is nil). What i'm doing wrong? Is this a right design?
Or, you could avoid this entire pattern as being overly clever and create a class factory method that returns either a BasicObject or an AdvObject depending on the parameters that were passed to it.
Your init... method would need to do a couple of things differently, as shown below:
- (id)initWithSomething:propertyOne andSomethingElse:propertyTwo
{
if (self = [super init])
{
if (!propertyTwo)
{
self = [[AdvObject alloc] initWithBasic:self];
}
_propertyOne = propertyOne;
_propertyTwo = propertyTwo;
}
return self;
}
I haven't actually tried this with ARC, so you'd need to test this carefully.

imageitem class define

i need to build an application that define an array that should be made of image items.
every image iten has an image, a name and a photographer name.
i build my image item class and i want you to check if my define is correct and good(i just start to learn objective c).
i want you to emphasize on the set's methods.
here is the photoitem.h:
#import <Foundation/Foundation.h>
#interface photoItem : NSObject
{
UIImage *imageView;
NSString *photoNameLabel;
NSString *photographerNameLabel;
UIButton *viewPhoto;
}
#property(readonly) NSString *name;
#property(readonly) NSString *nameOfPhotographer;
#property(readonly) UIImage *imageItem;
-(id)makePhotoItemWIthPhoto:(UIImage*)image name:(NSString*)photoName photographer: (NSString*)photographerName;
#end
here is my photoitem.m:
#import "photoItem.h"
#implementation photoItem
#synthesize name;
#synthesize nameOfPhotographer;
#synthesize imageItem;
-(id)makePhotoItemWIthPhoto:(UIImage*)image name:(NSString*)photoName photographer:(NSString*)photographerName
{
[self setName:photoName];
[self setNameOfPhotographer:photographerName];
[self setImageItem:image];
return self;
}
-(void) setName:(NSString *)name
{
photoNameLabel = name;
}
-(void) setNameOfPhotographer:(NSString *)nameOfPhotographer
{
photographerNameLabel = nameOfPhotographer;
}
-(void)setImageItem:(UIImage *)imageItem
{
imageView = imageItem;
}
#end
i hope you could fix my errors(if there are some).
thanks.
Two problems come to mind:
1) -(id)makePhotoItemWIthPhoto:name:photographer: might be better as -(id)initWithPhoto:name:photographer:. Otherwise the caller needs to alloc and init an object first so that self is valid, then call your method. At that point, the return of self doesn't make sense.
Example:
-(idinitWithPhoto:(UIImage*)image name:(NSString*)photoName photographer:(NSString*)photographerName {
self = [super init];
if (self) {
[self setName:photoName];
[self setNameOfPhotographer:photographerName];
[self setImageItem:image];
}
return self;
}
2) The three readonly properties don't seem to have any purpose since they have no connection to the variables that you initialize in the makePhotoItemWIthPhoto: method.

making class members properties and synthesizing them

Is it safe to say that if a class member does not need getter or setter functions then there's no point in making them properties and synthesizing them?
Well, yes, but often properties can be helpful in the implementation itself even if the properties won't be set outside of the implementation.
For example, suppose you had
#interface SomeObject : NSObject {
NSThing *thing;
}
#end
#implementation SomeObject
- (id)init {
if((self = [super init]))
thing = [[NSThing someThing] retain];
return self;
}
- (void)someMethod {
if(thing)
[thing release];
thing = [[NSThing someOtherThing] retain];
}
// etc etc
#end
Why would you want to bother having to check if thing had been allocated, release thing, set it to something else, and then retain it again, when you could simply do:
- (id)init {
if((self = [super init]))
[self setThing:[NSThing someThing]];
return self;
}
- (void)someMethod {
[self setThing:[NSThing someOtherThing]];
}
If you don't want to make these properties accessible outside of your class, you can use a category
#interface SomeObject ()
#property (retain) NSThing *thing;
#end
in your .m file.

Help with a method that returns a value by running another object's method

I have a Class that runs the following method (a getter):
// the interface
#interface MyClass : NSObject{
NSNumber *myFloatValue;
}
- (double)myFloatValue;
- (void)setMyFloatValue:(float)floatInput;
#end
// the implementation
#implementation
- (MyClass *)init{
if (self = [super init]){
myFloatValue = [[NSNumber alloc] initWithFloat:3.14];
}
return self;
}
// I understand that NSNumbers are non-mutable objects and can't be
// used like variables.
// Hence I decided to make make the getter's implementation like this
- (double)myFloatValue{
return [myFloatValue floatValue];
}
- (void)setMyFloatValue:(float)floatInput{
if ([self myFloatValue] != floatInput){
[myFloatValue release];
myFloatValue = [[NSNumber alloc] initWithFloat:floatInput;
}
#end
When I mouse over the myFloatValue object during debugging, it does not contain a value. Instead it says: "out of scope".
I would like to be able to make this work without using #property, using something other than NSNumbers, or other major changes since I just want to understand the concepts first. Most importantly, I would like to know what mistake I've apparently made.
I can see a couple of mistakes:
The line #implementation should read #implementation MyClass
The function setMyFloatValue is missing a closing ] and } —it should read:
- (void)setMyFloatValue:(float)floatInput{
if ([self myFloatValue] != floatInput){
[myFloatValue release];
myFloatValue = [[NSNumber alloc] initWithFloat:floatInput];
}
}
I've just tested it in Xcode and it works for me with these changes.
Why not just set property in interface and synthesize accessors in implementation?
#interface MyClass : NSObject {
float *myFloat
}
#property (assign) float myFloat;
#end
#implementation MyClass
#synthesize myFloat;
#end

Objective-C :: using a method to change an object

I have a class called "CardSet", containing an NSMutableArray* cardSet to hold "cards", which I extend to make "DeckCards". I'd like "CardSet" to have a method called "(void)addCard:(Card*)" (and similarly a method "removeCard"). I'd like "addCard" to some how have access to and set cardSet. Even better I'd like to use the "addCard" method to initialise cardSet. The class file "CardSet.h" reads:
#import < Cocoa/Cocoa.h >
#import < Card.h >
#interface CardSet : NSObject {
NSMutableArray* cardSet;
}
-(id)init;
-(NSMutableArray*)getCardSet;
-(void)setCardSet:(NSMutableArray *)new_cardset;
-(Card*)getCard:(NSInteger) index;
**-(void)addCard:(Card*) new_card;**
-(void)removeCard:(Card*) old_card;
-(void)dealloc;
#property (readwrite, retain, getter=getCardSet, setter=setCardSet) NSMutableArray* cardSet;
#end
and the method file reads:
#import "CardSet.h"
#implementation CardSet
-(id)init{
if( self = [super init] ){} //will add initialisations here later
return self;
}
-(NSMutableArray*)getCardSet{
return cardSet;
}
-(void)setCardSet:(NSMutableArray *)new_cardSet{
cardSet = new_cardSet;
}
-(Card*)getCard:(NSInteger)index{
return [cardSet objectAtIndex:index];
}
**-(void)addCard:(Card *)new_card{
[cardSet addObject:new_card];
}**
-(void)removeCard:(Card *)old_card{
[cardSet removeObject:old_card];
}
-(void)dealloc{
[cardSet release];
[super dealloc];
}
#synthesize cardSet;
#end
This compiles just fine. I'd like to initialise a "DeckCards" instance using its "addCard" method 52 times. When I call addCard 52 times in a DeckCards setter method, and ask for the size of its "cardSet", I'm returned 0.
This appears to be a scope or privileges problem? Can the "addCard" method have any setter privileges? Must a setter argument be the same as the return and respective member type?
[I can work around the above by creating an NSMutableArray object "deck_cards_temp" outside of "DeckCard", add 52 cards to this, and pass it to set the member of my "DeckCards" instance via the setter inherited from "CardSet". This is not very satisfactory!]
What do you advise? Many thanks in advance for your help and patience.
You are never actually creating the cardSet object. You should be creating it in your -init method:
-(id)init
{
if( self = [super init] )
{
cardSet = [[NSMutableArray alloc] init];
}
return self;
}
Because you never actually create the array, all the calls to -addCard: are being sent to a nil object.
When you pass in an array to -setCardSet:, you are passing in an initialized array so the array is no longer nil and the -addCard: calls work fine.
CardSet.h
#import <Cocoa/Cocoa.h>
// For know we just need to know there is a class named "Card" being used but implemented later
#class Card;
#interface CardSet : NSObject {
NSMutableArray *cardSet;
}
// Here are the methods according to "correct" naming conventions
- (Card *)cardAtIndex:(NSInteger)index;
- (void)addCard:(Card *)card;
- (void)removeCard:(Card *)card;
// This will help us and forget about writing the setter/getter
#property (nonatomic, retain) NSMutableArray *cardSet;
#end
CardSet.m
#import "CardSet.h"
// Now we tell the compiler what "Card" is and what methods etc. it has
#import "Card.h"
#implementation CardSet
#synthesize cardSet;
- (id)init {
if (self = [super init]) {
// If we don't create the cardSet, how are we able to work with it!?
NSMutableArray *anArray = [[NSMutableArray alloc] init];
self.cardSet = anArray;
[anArray release];
}
return self;
}
- (Card *)cardAtIndex:(NSInteger)index {
return [cardSet objectAtIndex:index];
}
- (void)addCard:(Card *)card {
[cardSet addObject:card];
}
- (void)removeCard:(Card *)card {
[cardSet removeObject:card];
}
- (void)dealloc {
[cardSet release];
[super dealloc];
}
#end
As Abizern already noted: Naming the array the same as your class is a bad thing.
I would shorten that init method:
- (id)init {
if (self = [super init]) {
// If we don't create the cardSet, how are we able to work with it!?
self.cardSet = [NSMutableArray array];
}
return self;
}