1

I have a instance variable mTeacher in my School class:

@interface School : NSObject {
     Teacher *mTeacher;
}
@end

In implementation file, I have method - (Teacher *)getTeacher which is supposed to return either the existing teacher instance if there is one or create one and return it:

- (Teacher *)getTeacher {
    if (mTeacher != nil) {
        return mTeacher;
    }
    return [[Teacher alloc] init];
}

There could be multiple other instance methods calling this method to get the Teacher instance & assign to mTeacher instance variable:

- (void)methodOne {
   mTeacher = [self getTeacher];
   ...
}

- (void)methodTwo {
   mTeacher = [self getTeacher];
   ...
}

So, if one of the method assigned already an instance of Teacher to mTeacher, the other method when calling [self getTeacher] would end up with mTeacher = mTeacher underneath (because - (Teacher *)getTeacher method simply returns mTeacher in this case). My question is , is it fine in objective-C ? Any potential issues with my getTeacher method?

Simon Bosley
  • 1,114
  • 3
  • 18
  • 41
Leem.fin
  • 40,781
  • 83
  • 202
  • 354
  • You're implementing the Singleton design pattern. Here's another related post on the topic that should help: http://stackoverflow.com/questions/145154/what-should-my-objective-c-singleton-look-like – Simon Bosley May 31 '16 at 12:39
  • 1
    I don't see anything technically wrong with it, but why not just initialize the variable once in an `init` method and use it where needed rather than trying to set it multiple times? (On style: it would be more in keeping with Objective-C to make `teacher` a property rather than an explicit variable. Then, along with my suggestion about `init`, the "getter" would disappear from your code.) – Phillip Mills May 31 '16 at 12:40
  • If `mTeacher` is never `nil`, why don't you initialize it in the `School`'s `init` method ? Also, you should check this out [Properties in Objective-c](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html) – Sudo May 31 '16 at 12:43

4 Answers4

1

It looks like you want to instantiate the variable lazily.

The usual pattern in Objective-C is to declare a readonly (nonatomic) property and use the backing instance variable for the initialization.

@interface School : NSObject 

@property (readonly, strong, nonatomic) Teacher *mTeacher;

@end

@implementation School
@synthesize mTeacher = _mTeacher;

- (Teacher *)mTeacher {
    if (!_mTeacher) {
        _mTeacher = [[Teacher alloc] init];
    }
    return _mTeacher;
}

@end

Edit: Without using a property access the instance variable directly:

@interface School : NSObject
{
  Teacher *mTeacher;
}

@end

@implementation School

- (Teacher *)mTeacher {
  if (!mTeacher) {
     mTeacher = [[Teacher alloc] init];
  }
  return mTeacher;
}

@end

However if you want to use explicitly the getter rather than the instance variable you have to write

[self mTeacher];
vadian
  • 274,689
  • 30
  • 353
  • 361
1

The approach is correct, but there are two remarks:

A. You can never have a "no teacher" scheool, that means the property nil'd – for whatever.

B. Obviously you start with Objective-C coming from another language:

  • Do not use a m prefix for "members". (They are no member, but ivars.)

  • Do not declare ivars in interface.

  • Do not use a get prefix for getters.

You can use properties as mentioned by vadian:

@interface School : NSObject 
@property (readonly, strong, nonatomic) Teacher *teacher; // without m
- (Teacher*)teacher; // *Alternatively* without @property
@end

@implementation School
// usually the ivar is created implicitly with the name _teacher. 
// However, you have a readonly property and overwrite all accessors 
// (in the case of a read only property there is only a getter) of the property, 
// no ivar will be created automatically. You have to do that explicitly.
{
    Teacher *_teacher;
}

- (Teacher *)teacher { // no m
  if (!_teacher) 
  {  
    _teacher = [[Teacher alloc] init];
  }
  return _teacher;
}
@end

Additionally this code is not thread-safe.

Amin Negm-Awad
  • 16,582
  • 3
  • 35
  • 50
0

It is fine with objective c..!! You should not got issue with this i think but you can check with if - else like,

 - (void)methodOne {

    if(!mTeacher){
    mTeacher = [self getTeacher];
    }
    ...
  }

So, if mTeacher is not nil then only it will called getTeacher.

In objective c, you can use property for this. It will set getter and setter methods of it. Or you need this object to initialize once in init method. no need to do like this.

Ketan Parmar
  • 27,092
  • 9
  • 50
  • 75
0

Nothing wrong with this approach, why can't you create Teacher object in School init. And also if you are working on a multithreading environment make sure you are not creating the Teacher object multiple times.

Feroz
  • 699
  • 5
  • 17
  • 25
  • You are right that the code is not thread-safe. But making solely accessors thread-safe is meaningless in many cases. (That's why nearly nobody uses atomic accessors.) However, if you want to have thread-safeness, one should use GCD in nowadays. – Amin Negm-Awad May 31 '16 at 13:13
  • I mean we should guard the the place where we are creating instance (init method), not the accessor. – Feroz May 31 '16 at 13:44
  • 1
    @Feroz: Lazy initialisation is _very_ useful and in many cases essential. – gnasher729 May 31 '16 at 14:20
  • @gnasher729: Yup Agreed. – Feroz May 31 '16 at 14:28
  • Every access to a `Teacher` instance is potentially a subject of thread-safety. This is no reason to make all the code thread-safe. – Amin Negm-Awad May 31 '16 at 17:55
  • 1
    I'm not denying that, I'm just telling to ensure thread safety while creating instance, Is anything wrong with that statement? – Feroz May 31 '16 at 18:23