Xcode / iOS Automatic Delegate Assignment... A bug? - ios

I found some unexpected behavior when debugging one of my table views.
My tableView in the storyboard does not have its delegate or dataSource set.
However, at the breakpoint in this snippet, both are set to the view controller. I've checked my entire viewDidLoad hierarchy and at no point is the delegate set.
My question is: is this expected behavior? or is it a bug in Xcode or the SDK?

If your view Controller is a UITableViewController, then the delegate and data source of the table view it is the controller for is set to itself unless they are set in Interface Builder.

Related

What is the Swift iOS purpose of dragging datasource and delegate?

http://teachyourselfios.com download v9 open FlowerDetail. Look at story board, look at Master Scene Table View, and remove both Outlets, datasource and delegate. Everything runs fine without the dragging of datasource and delegate. Datasource and delegate in MasterViewController is not programmatically set.
What is the swift iOS purpose of dragging datasource and delegate?
If the view controller is a UITableViewController (or a UICollectionViewController), the setting of these outlets is not necessary. And in this case, the MasterViewController is a UITableViewController.
But sometimes you have a plain old UIViewController and manually add a UITableView (or UICollectionView) to the scene's main view (you do this if you have other controls you want to put on the view in addition to the table/collection view), in which case setting these outlets (or doing it programmatically) is critical. So it's important to know how to do this in those cases where it's needed.

iOS: show segue prevents UITableViewController to auto scroll when UITextField gets focus

I have a UITableViewController that is presented via a show (push) segue. Its rows have UITextFields. On the iPhone, when a textfield get focus, the keyboard hides the textfield if said textfield is towards the bottom of the screen.
This only happens on the iPhone, with any segue except "present modally" or "present as popover" ones. For these latter segues, the table scrolls up the textfield so that it's not covered by the keyboard - the standard behavior for UITableViewController.
On the iPad it works as expected (auto-scrolling the table), regardless of the segue type. Any idea why?
I've created a new project just to test this, it works as expected. In the initial project where it doesn't work, the UITableViewController is a secondary controller of a SplitViewController.
I've tested with or without auto-layout, same results.
iOS8
Thanks
The first screenshot shows the table with no textfield having focus
The second one was taken after the last textfield got focus. It is covered by the keyboard.
PS: I've tried the same with just a UITableViewController, not a subclass of UITableViewController as initially. I know in subclasses there is a problem if for example you override viewWillAppear but do not call super. This is not the case.
Relevant Apple documentation excerpt:
Note: A table view controller supports inline editing of table view rows; if, for example, rows have embedded text fields in editing mode, it scrolls the row being edited above the virtual keyboard that is displayed. It also supports the NSFetchedResultsController class for managing the results returned from a Core Data fetch request.
The UITableViewController class implements the foregoing behavior by overriding loadView, viewWillAppear:, and other methods inherited from UIViewController. In your subclass of UITableViewController, you may also override these methods to acquire specialized behavior. If you do override these methods, be sure to invoke the superclass implementation of the method, usually as the first method call, to get the default behavior.
https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/TableView_iPhone/TableViewAndDataModel/TableViewAndDataModel.html#//apple_ref/doc/uid/TP40007451-CH5-SW7
I have checked the behaviour and faced this kind of issue in iPhone 6.
In viewDidLoad method -
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
I wish I could tell you why the code below works, but I can't; I am aware that makes this a bad answer. With that said, it does work consistently across my application.
Add a simple completion block to your view controller dismissal. In my code, that means the viewWillAppear is called twice, once before dismissal and once after (as I said, I don't know why this works but it does for me).
dismissViewControllerAnimated(true) { self.viewWillAppear(true) }

UISplitViewController with custom master view controller that is not UITableViewController

I'm working on an iPad application that requires a UISplitViewController. For the Master view controller I would like to use a custom view controller that has an image, a table view , and a label. Out of the box the UISplitviewcontroller/MasterDetail template give me a Navigation controller with an embedded UItableViewcontroller. When I attempt to change out the tableview controller for a new Viewcontroller the view for the new controller is not being presented. I am able to set the UIBarbuttons but none of the datasource methods for the table view are being called. Also the imageview and the label are not being presented. I've made sure that my view controller is the delegate and datasource for the tableview and set the preferred size in the awake from nib still no UI. I'm adding the UISprlitviewcontroller to an existing project could this be an issue?
The issue was with the use of size classes. Since this is an iPad app only I turned off the size classes option and the app is working as expected. I need to invest time in learning how to properly use this new feature.

Is it possible to re-assign an existing UITableView to a different UITableViewController?

Most of my app is created programmatically, but I have a handful of complex views that are created using Interface Builder and loaded programmatically.
In one view I have a UITableViewController subclass created programmatically, and its tableView property is assigned to the UITableView instance in the XIB, referenced as an IBOutlet. This happens in the XIB's UIViewController's viewDidLoad, and the table view displays correctly.
At one point, I need to change the entire contents of the table view. Ideally, I would like to disconnect that view from the first UITableViewController and connect it to a different one that will feed it different data. Attempting to assign the view to the new controller's tableView property results in "A view can only be associated with at most one view controller at a time!" Assigning the previous controller's tableView to nil before assigning the new one avoids the error, but the table view disappears from the screen.
Honestly, I know the table view instance is usually managed by the UITableViewController. I can't find anything in the docs about setTableView automatically setting the back references for delegate and dataSource in an assigned tableView, so I'm surprised my externally-created tableView works in the first place. In fact, the TVC docs seem to discuss UITableViewController's tableView property as readonly, even though it is not tagged as such.
I'm sure I don't have all your information, but on the surface it seems that you are making this more complicated than it needs to be. Why don't you just use the current UITableViewController and corresponding UITableView and reload it with "new data". Alternatively, just programmatically create another UITableViewController and use that for your new data. Is there a compelling reason to recycle the UITableView?
The answer is no, and here's why:
I checked with the debugger, and the normal setTableView does set the view property on self as well as setting the delegate and dataSource properties on the new incoming tableView. This is not documented by Apple, but it was the assumed behaviour and so it was all well and good.
What I did not realize is that the default setView (from UIViewController) will remove an existing view from its superview before setting the new one. To prevent the "one view controller at a time" runtime error I was setting the old TVC's tableView to nil, which caused the tableView I intended to reuse to be removed from the view hierarchy. To avoid this behaviour, one would have to override setView, which is more complicated than I care to get into for this task.
Reusing views (in this case, a UITableView instance) is not supported by Apple. It is not mentioned in the UITableViewController documentation, but it is mentioned in the UITableViewController documentation regarding the view property. Arguably, UITableViewController's tableView property should be marked readonly by Apple, with its tableView solely managed internally, but there's probably a good reason why its not.

In IB, Cannot Connect IBOutlet Delegate to Another View Controller?

I have a view controller which as one of its views a container view (in IB storyboard) which embeds a table view controller, which in turn has a container view that embeds yet another view controller. In this last view controller I set up a delegate protocol with a weak synthesized delegate property as an IBOutlet. The very first view controller is what I want to receive the delegate methods from the last and I added the protocol <...> to it.
The problem is that I have not figured out a way while in storyboard (or otherwise) to link the IBOutlet delegate of the last view controller to the first view controller which follows the protocol so the last can send the first messages. I thought I could just drag and drop (with the control key) but all I find is segue options on the destination. It seems even though the delegate appears in the outlet connections window, it will not connect to ANY view controller in my project.
Can't ANY view controller be a delegate of another's protocol? And can be linked in IB? If I cannot do it with IB, I don't know how to make another VC a delegate upstream.
Any advice would be appreciated. Thanks.
You cannot connect IBOutlets between view controllers. You need to do it in code. You'll have to go through the chain of childViewController to get from the first controller to the last -- if I understand your structure properly, from the first view controller:
LastController *last = ((UIViewController *)self.childViewControllers[0]).childViewControllers[0];
last.delegate = self;
I asked a similar question Interface Builder won't allow connections to custom UIView class? I ultimately opened a bug with Apple. After a few follow up queries from Apple, I haven't heard any kind of resolution.

Resources