4

I'm unsure how I should initialise the various properties in an objective-C class. Please assume I'm a very new user to Objective-C in your answers...

I have the following classes:

Test class

@interface Test : NSObject
@property (nonatomic, strong) NSString *name;
@end

TestManager class

@interface TestManager : NSObject
@property (nonatomic, strong) NSMutableArray *tests; // array of Test objects (array size unknown until runtime)
@end

Controller class

@interface TestController : NSObject
@property (nonatomic, strong) TestManager *aManager;
-(void)initManager;
-(void)doSomething;
@end

I want to have an method like initManager called:

-(void)initManager
{
    // how can I init the aManager which will have an array of Test objects
}

which will automatically allocate an array of objects to be stored inside the manager class so I can do things like:

-(void)doSomething
{
   NSString *name = ((Test *)[self.aManager.tests objectAtIndex:0]).name;
}

I'm not even sure that initManager is the correct method to use - is there something built in that always gets called?

5
  • 2
    @HotLicks - Why not post an answer with a link to a good book instead of sniping? Commented Jul 8, 2013 at 21:35
  • @RogerNolan Because that wouldn't be a complete answer Commented Jul 8, 2013 at 21:37
  • no but every little bit helps right. Commented Jul 8, 2013 at 21:38
  • @RogerNolan - A couple are listed here. Of course, any attempt to collect a list is shouted down. Commented Jul 8, 2013 at 22:54
  • 2
    Should not have been closed. This is a good community question and has been reworded to be clear. Commented Jul 15, 2013 at 23:37

3 Answers 3

13

Firstly, let's look at the way we can initialize your Test class objects.

You can also write some initialization method for your Test class so instead of this:

Test example = [[Test alloc] init];
example.name = @"s";

you can write something like this:

Test example = [[Test alloc] initWithName:@"s"];

Please note that this is very common for initialization method to return newly created object, hence the initialization method usually returns 'id' type (not void).

This is the implementation for your test class which will be used in examples below.

.h file:

- (id)initWithName:(NSString *)aName;

.m file:

- (id)initWithName:(NSString *)aName 
{
   self = [super init];
   if (self) {
     _name = aName;
   }
  return self;
}

You can initialize your TestController class this way:

.h file:

- (id)initManager;

.m file:

- (id)initManager
{
  self = [super init]; //always call the superclass init method when your class inherit from other class
  if (self) { // checking if the superclass initialization was fine
    _tests = [NSMutableArray array];
    [_tests addObject:[[Test alloc] initWithName:@"s"]]; 
    [_tests addObject:[[Test alloc] initWithName:@"l"]];
  }
  return self;
}

Or something like this:

- (id)initManager
{
  self = [super init]; //always call the superclass init method when your class inherit from other class
  if (self) { // checking if the superclass initialization was fine
    _tests = [NSArray arrayWithObjects:[[Test alloc] initWithName:@"s"], [[Test alloc] initWithName:@"l"]];
  }
  return self;
}

Like the @Andrew said it is better to use alloc + init. Here are some examples of this syntax:

CGRect rect = CGRectMake(0, 0, 100, 100);
[[UIView alloc] initWithFrame:rect];

[[NSArray alloc] init]

This is the common way to initialize objects. Despite having this mechanism there are also some additional methods (which are in fact static functions) which give the programmer the nice way to initialize objects. Using them u don't have to write keyword 'alloc' so that the code is shorter and easier to read.

[NSArray array] //creates and returns empty array
[NSMutableArray array] //creates and return empty mutable array

[UIButton buttonWithType:UIButtonTypeContactAdd]; //creates and return button
Sign up to request clarification or add additional context in comments.

1 Comment

Don’t Use Accessor Methods in Initializer Methods and dealloc developer.apple.com/library/ios/documentation/Cocoa/Conceptual/…
2

first import header files of test, and test manager class, into controller class

#import Test.h
#import TestManager.h

then in controller class

-(void)initManager
{
    TestManager *aTestManager = [TestManager new];

    Test *test1 = [Test new];
    Test *test2 = [Test new];

    [aTestManager.tests addObject:test1];
    [aTestManager.tests addObject:test2];
}

5 Comments

Its better to use alloc+init
@AndrewShmig I wouldn't use "better", how about "more Objective-C." new has a very limited use case, and conciseness is one of them.
new method is a combination of alloc and init. But using default initialiser new method will restrict you from defining you own custom initialiser.
@AndrewShmig why is it better to use alloc+init?
1

Let's start at the top. You probably can and should make the name readonly.

(Demos assume ARC is enabled)

@interface Test : NSObject
@property (nonatomic, readonly) NSString *name;

// and then simply initialize name:
- (instancetype)initWithName:(NSString *)pName;

@end

NSString properties should be copied:

@implementation Test

- (instancetype)initWithName:(NSString *)pName
{
 self = [super init];
 if (nil == self) return nil;
 // copy the NSString:
 // don't use getters/setters in initializers or -dealloc
 _name = pName.copy;
 return self;
}

@end

Similarly readonly:

@interface TestManager : NSObject
@property (nonatomic, strong, readonly) NSMutableArray *tests; // array of Test objects (array size unknown until runtime)
@end

@implementation TestManager

- (id)init
{
 self = [super init];
 if (nil == self) return nil;
 // just initialize readonly tests:
 _tests = NSMutableArray.new;
 return self;
}

@end

Then TestController could probably use a readonly TestManager and borrow the form used above. Otherwise, it can be readwrite, if needed.

// don't declare/implement an instance method
// which has the prefix -init*, like initManager. renamed.
 - (void)resetManager
 {
  // if readonly is ok, then just create it in the initializer.
  // otherwise, if you need the ability to set the manager in the controller,
  // then declare the property readwrite and:
  self.testManager = TestManager.new;
  // note: aManager is not a good name. renamed to testManager.
 }

- (void)doSomething
{
 assert(self.testManager && "did you forget to init the manager?");
 Test * test = [self.testManager.tests objectAtIndex:0];
 NSString * name = test.name;
 ...
}

This is far from covering all initialization cases in ObjC, but it is a start.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.