iOS Viewcontroller with reference to table view IBOutlet - Weak or Strong? - ios

As I read in another question, a rule of thumb was:
When a parent has a reference to a child object, you should use a strong reference. When a child has a reference to its parent object, you should use a weak reference or a unsafe_unretained one (if the former is not available). A typical scenario is when you deal with delegates. For example, a UITableViewDelegate doesn't retain a controller class that contains a table view.
Well, in this case I have a view controller with a table view IBOutlet. This table view also uses the view controller as a delegate and data source. By the rule above, the view controller acts as the parent and so I should have a strong reference to the table view - the table view should have a weak reference to the view controller.
I'm not sure how to define that latter weak reference - I'm setting
tableView.delegate = self;
tableView.dataSource = self;
How am I supposed to make myself weak? Or is this not the right way to do it?

You can just drag the outlet from your UITableView to your .h file. Xcode will create appropriate property for you. You can choose weak/strong type from there as well while naming the Outlet.
If you would however like to create it manually, you can add this line to your .h file:
#property (weak, nonatomic) IBOutlet UITableView *tblView;
But do keep in mind that even after adding this line to your .h. file, you will still have to connect it to your UITableView.
Also don't forget to make your ViewController conform to UITableViewDelegate like below:
#interface MyTableViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
In your title however, you seem to be confused about the difference between Weak and Strong properties. Ole Begemann has answered about the difference splendidly on This question.

The code you wrote is fine. You don't have to make yourself weak. The delegate and datasource properties are declare as weak in the UITableView definition.

delegate and datasource are already weak as per UITableView.h.
#property (nonatomic, weak, nullable) id <UITableViewDataSource> dataSource;
#property (nonatomic, weak, nullable) id <UITableViewDelegate> delegate;
If any instance is set as delegate and datasource won't get retained by tableview instance
And when you make a IBOutlet make it like this. Choose weak if its strong by default its weak as shown in image
#property (weak, nonatomic) IBOutlet UITableView *tableview;
As the view is already retained by the view it's added (i.e self.view)

It is just like a view in UIKit Control to display data in list form. It is not a child controller. All UIKit items are referenced as weak.

Related

iOS: __weak vs (weak)

Are there a differences between these two lines of code?
__weak IBOutlet UITextField *usernameField;
#property (weak) IBOutlet UITextField *usernameField;
What if you declare either of these in interface section of the .h or the .m files?
Yes. The first example declares a weak instance variable called usernameField, but the second declares a weak property called usernameField, and an instance variable called _usernameField that is accessed by the property.
If you declare it in an #interface section of the .m file, then it can only be accessed in that .m file (unless you mess with the Objective-C runtime).
The difference is not in the weak reference but just in the fact that the first is an instance and the second is a #property.
__weak and (weak) is the same thing, but the second is used as attribute for properties.

UITableView (IBOutlet) becomes null after initial data loaded

This has been driving me mad - I have a Class ParentViewController (no xib) with #property picTable, and then ChildViewController (subclass of ParentViewController) with xib and the picTable part of File's Owner linked up.
I noticed the problem as I need to add in more data from a URLRequest - I have the data in an NSArray, but calling reloadData does nothing - and breakpoints are showing that self.picTable is then null - but it is definitely linked (checked via breakpoints) earlier in the view's lifecycle.
I've tried using NSNotificationCenter, a dispatch queue and [self performSelectorOnMainThread... all to no avail - my refreshTableView is always called but the breakpoints show the table view as null.
Tried -
#property (nonatomic, strong) IBOutlet UITableView *picTable;
And -
#property (nonatomic, retain) IBOutlet UITableView *picTable;
Links to the two classes:
Parent:
https://github.com/gileze33/Ticklr/blob/master/Ticklr/GWTPicPresentingViewController.h
https://github.com/gileze33/Ticklr/blob/master/Ticklr/GWTPicPresentingViewController.m
Subclass:
https://github.com/gileze33/Ticklr/blob/master/Ticklr/GWTPicViewController.h
https://github.com/gileze33/Ticklr/blob/master/Ticklr/GWTPicViewController.m
Even though you call [super initWithNibNamed...] from the subclass, I'm doubtful that the nib is hooking up the tableview to the superclass. Even if it is important to your design to have the tableView property defined in the superclass, try moving the tableView property down to the subclass and see if it works then.

Set delegates to nil under ARC?

I'm writing iOS apps using ARC and targeting iOS 5+.
Suppose I write a custom view object that has a delegate property. In declaring the delegate property, I make it a weak reference to avoid a retain cycle, so that when the actual delegate object (the controller) is destroyed, my custom view will also be destroyed, as follows:
#interface MyCustomView : UIView
#property (nonatomic, weak) id<MyCustomViewDelegate> delegate;
#end
All is good.
Ok, so now I'm writing the controller object, and it has references to two view objects: my custom view and an Apple-supplied UIKit view, both of which declare delegate properties, and the controller is the delegate for both views. Maybe it looks something like this:
#interface MyViewController : UIViewController <MyCustomViewDelegate, UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, strong) MyCustomView *customView;
#property (nonatomic, strong) UITableView *tableView;
#end
#implementation MyViewController
- (void)viewDidLoad
{
self.customView.delegate = self;
self.tableView.dataSource = self;
self.tableView.delegate = self;
}
#end
My question is this: Do I need to override dealloc to set either or both delegates to nil?
I mean, as I understand it, the delegate property of the UIKit view (in this case, tableView) isn't actually declared to be a weak reference, but rather an __unsafe_unretained reference, for backwards compatibility with non-ARC version of iOS. So maybe I need to write
- (void)dealloc
{
_tableView.dataSource = nil;
_tableView.delegate = nil;
}
Now, if I do have to override dealloc, I still don't have to set _customView.delegate = nil, right? Because that was declared (by me) to be a weak reference, so it should be set to nil automatically upon the destruction of MyViewController.
But on the other hand, I'm not targeting non-ARC versions of iOS, nor do I intend to. So maybe I don't need to override dealloc at all?
Setting non-weak delegates to nil is generally a good idea unless you know you don't have to. For UITableView and UIScrollView, I've experienced crashes on previous iOS versions with the following steps (it may help to run with zombies enabled):
Scroll really fast.
Press Done or the back button or whatever to dismiss the VC.
This appears to happen because the scrolling animation is retaining a reference to the view, so the view outlives the VC. It crashes when sending the scroll event.
I've also seen crashes after dismissing a VC containing a UIWebView while a request is being loaded, where simply setting the delegate to nil was not sufficient (I think the workaround was to call [webView loadRequest:nil]).
If the only strong reference to said tableView is your sole MyViewController controller, you don't need to manually set UITableViewDelegate or UITableViewDataSource to nil.
The reason is that once the dealloc method on your MyViewController is called, the tableview will also be destroyed along with the controller (that is, once again, as long as the only reference to it is your sole controller MyViewController class).
If you have other strong references to this tableview, such as other controllers, it would then be possible that the tableview could then exist longer than the MyViewController class. In such a case, it would be necessary to set the UITableViewDelegate and UITableViewDataSource to nil in the dealloc method of MyViewController because, as you mentioned, these properties are NOT weak references and will not automatically be set to nil.
However, this sort of situation is pretty rare in my experience though.
Most of the time, I don't worry about setting these to nil honestly, but it is a defensive programming practice.
See this post also:
In dealloc method set any delegate to nil is needed or not needed
The only reason you would want to explicitly set the delegate and dataSource to nil is if the customView or the tableView could out live the view controller. Setting them to nil would guard against the delegate or dataSource referencing a deallocated object.
If the customView and tableView will be deallocated along with the view controller, there is no need to nil out the delegate and dataSource.

addSubview for Storyboard created views

At least I think it's a basic problem. I just started working with views programmatically.
In RouteCaptureViewController.h:
#property (strong, nonatomic) IBOutlet UIView *routeCaptureSuperView;
#property(nonatomic, weak) IBOutlet UIImageView *captureImageView;
#property(nonatomic, retain) IBOutlet UIImageView *previewImageView;
#property (weak, nonatomic) IBOutlet UIView *captureRouteButtonView;
In my storyboard:
All of the outlets are properly connected, I checked.
I'm implementing addSubview in a method as such and nothing happens:
[self.routeCaptureSuperView addSubview:self.captureRouteButtonView];
[self.routeCaptureSuperView addSubview:self.captureImageView];
The following lines worked previously in the code:
[self.captureImageView removeFromSuperview];
[self.captureRouteButtonView removeFromSuperview];
And I know self.routeCaptureSuperView is not nil from an NSLog.
If I understood you correctly and you removed the views to add them again later I can make an educated guess:
In the moment you send removeFromSuperview to your views they get deallocated because they are declared as weak only.
Weak means that the property will be nil'd if the object is deallocated because the last strong relationship to that object is released.
The parent view is the object that keeps the last strong relationship to those two views.
Try to change weak to strong in the #property declaration of the two subviews.

Should all reference to programmactically created subviews declared as weak?

I am getting confuse weither reference to subviews i am creating in a view should be declared with the weak or strong keyword when using ARC in iOS5.
Here is a sample of my header file:
#import <UIKit/UIKit.h>
#import <MessageUI/MessageUI.h>
#class SCLGridView;
#interface MyViewController : UIViewController <UIPopoverControllerDelegate, MFMailComposeViewControllerDelegate>
#property (weak, nonatomic) IBOutlet UIView *hiddenBrowserView;
#property (strong, nonatomic) SCLGridView *gridView;
#property (strong, nonatomic) UIImageView *backgroundView;
#property (strong, nonatomic) UIView *backgroundShadowView;
#property (strong, nonatomic) UIPopoverController* popOverController;
#end
I run under the impression that the views i am creating and want to reference should be declare with the strong keyword because i am owning those views(i create them). However i have declared the hiddenBrowserView as weak because i am referencing a view i have created in the storyboard. Is this apporach correct or i should make all those view reference as weak even for the reference to views i create programmatically? Thanks!
As far as I know the subviews are strongly referenced by the main view of your controller. So there is no purpose of referencing them strong because the'll be useless when your main view goes down.
In other way, you create a subviews programmatically, and add them to your controller's main view.
Your controller's main view references them strongly.
And you point at this views with weak properties.
When your controller's main view is deallocated, so are the subviews.

Resources