1

I am writing a small test program using Xcode 5.1.1, for iOS 7.1. I am not using Xib or Storyboard. Everything is done programmatically. In the AppDelegate.m, I create an instance of my TestViewController and set it as the rootViewController of the window. Inside TestViewController.m, I override the "loadView" to create and assign the main view of the controller.

TestViewController.h
--------------------
  @interface TestViewController : UIViewController
  @property (nonatomic, weak) UILabel *cityLabel ;
  @end

TestViewController.m
--------------------
  @implementation TestViewController

  - (void)loadView
  {
      UIView *mainView = [[UIView alloc] init]  ;
      self.view = mainView ;
  }

  - (void) viewDidLoad
  {
      UIView *addressView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)] ;
      [self.view addSubview:addressView] ;

      [self createCityLabel:addressView] ;
  }

  - (void) createCityLabel:(UIView *)addressView
  {
      // Warning for below line - Assigning retained object to weak property...
      self.cityLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 80, 30)] ;

      [addressView addSubview:self.cityLabel] ;
  }

  @end

As per my understanding, the ownership is as follows

testViewController ---(strong)--> self.view --(strong)--> object of addressView --(strong)--> object of self.cityLabel.

Hence, self.cityLabel can be a weak reference to its target Object

self.cityLabel --(weak)--> object of self.cityLabel.

I did go through some other questions here on similar issues. Everywhere it is suggested to keep the IBOutlet properties inside the ViewController as "weak" (though not mandatory unless there is cyclic reference). Only strong reference maintained is to the main view of the controller.

However, I am getting a warning inside the createCityLabel function as indicated. This goes away if I remove the "weak" attribute. This is really confusing. Is the suggestion to keep Outlets as weak applicable only to those created using Xib/Storyboard?

programmist
  • 564
  • 1
  • 7
  • 24
  • 1
    possible duplicate of [objective c class method returned value, assigned to weak/strong properties](http://stackoverflow.com/questions/13729603/objective-c-class-method-returned-value-assigned-to-weak-strong-properties) – Paulw11 Apr 15 '14 at 07:00
  • Sidenote: your code doesn't actually compile with using `addSubView:` does it? It should be `addSubview:` (note the `v` is not capitalized). – Neil Apr 15 '14 at 07:20
  • @Neil, corrected the typos. This is just a sample program I typed in. – programmist Apr 15 '14 at 08:02

1 Answers1

8

Your cityLabel property can be weak, but you must add it to the view hierarchy before you can assign the property or assign it to a standard (strong reference) variable.

What is going on is that you're creating a UILabel, then assigning it to a property which assumes no ownership of it (weak). After you've gone past the self.cityLabel = [[UILabel alloc] ... line, the UILabel has already been deallocated and the cityLabel property is nil.

This will correctly do what you intend:

UILabel *theLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 80.0f, 30.0f)];
self.cityLabel = theLabel;
[addressView addSubview:theLabel];

The variable theLabel will retain the UILabel during for scope of createCityLabel: and adding the UILabel as a subview to a view that is part of the View Controller's view will retain it for the life of the view controller (unless you remove the UILabel from the view or any of the UILabel's parent views)).

meaning-matters
  • 21,929
  • 10
  • 82
  • 142
Neil
  • 1,813
  • 1
  • 12
  • 20
  • I had the wrong impression that it will stay allocated at least until the stack frame unwinds, before which the strong pointer is handed over the reference. Merciless deallocation :( But it makes sense, that at least one strong owner should be there to assume that the object is alive. In the case of Xib, the order must be other way around. Long way to go from C++ to objective C :) – programmist Apr 15 '14 at 08:18
  • 2
    Yes, in the case of the .xib, the view immediately retains the view. You could have done [addressView addSubview:[[UILabel alloc] init]] which would add it to the view and become retained, but it should be obvious that it becomes awkward to access the object you just created (you would have to go through the view subviews and find it). – Neil Apr 15 '14 at 08:28
  • 2
    I suspect that doing [addressView addSubview:(self.cityLabel = [[UILabel alloc] init])]; should work as intended. The object should remain allocated for as long as it's being "assigned" to things. – Neil Apr 15 '14 at 08:32