3

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?

Rog
  • 17,070
  • 9
  • 50
  • 73
user2543991
  • 615
  • 3
  • 8
  • 16
  • 2
    @HotLicks - Why not post an answer with a link to a good book instead of sniping? – Rog Jul 08 '13 at 21:35
  • @RogerNolan Because that wouldn't be a complete answer – JustSid Jul 08 '13 at 21:37
  • no but every little bit helps right. – Rog Jul 08 '13 at 21:38
  • @RogerNolan - A couple are [listed here](http://stackoverflow.com/questions/6633951/recommended-books-for-objective-c). Of course, any attempt to collect a list is shouted down. – Hot Licks Jul 08 '13 at 22:54
  • 2
    Should not have been closed. This is a good community question and has been reworded to be clear. – Rog Jul 15 '13 at 23:37

3 Answers3

12

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
Rafał Augustyniak
  • 2,011
  • 19
  • 14
  • Don’t Use Accessor Methods in Initializer Methods and dealloc https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmPractical.html – MacMark May 22 '14 at 13:35
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];
}
khanh.tran.vinh
  • 655
  • 5
  • 10
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.

justin
  • 104,054
  • 14
  • 179
  • 226