In my app, I have a summary page which will display the summary of payers and recipients list of each payer. That is, the summary page will have a list in the left side and clicking on each list will show its details on the right side(iPad). In order to re-use the same code for iPhone version too, I have it as separate view controllers. That is, I have a base ViewController(SummaryViewController). In this i subview the ViewController of the list(SummaryListViewController) and ViewController of the details(SummaryDetailViewController). Now, when the base view controller SummaryViewController loads, i subview the list and detail view controllers like this
//ListView is a view in the base ViewController to which i subview the list ViewController
let listViewController = SummaryListViewController(nibName:"SummaryListViewController", bundle: nil)
addChildViewController(listViewController)
listViewController.view.frame = CGRect(x: 0, y: 0, width: self.ListView.frame.size.width, height: self.ListView.frame.size.height)
ListView.addSubview(listViewController.view)
listViewController.didMove(toParentViewController: self)
//DetailView is a view in the base ViewController to which i subview the Detail ViewController
let detailViewController = SummaryDetailViewController(nibName: (UIDevice.current.userInterfaceIdiom == .pad ? "SummaryDetailViewController" : "SummaryDetailViewController_iPhone"), bundle: nil)
addChildViewController(detailViewController)
DetailView.frame = CGRect(x: DetailView.frame.origin.x, y: DetailView.frame.origin.y, width: self.DetailView.frame.size.width, height: self.DetailView.frame.size.height)
DetailView.addSubview(detailViewController.view)
detailViewController.didMove(toParentViewController: self)
Now, the prob is, I have to call a method in the SummaryDetailViewController from the tableView-didSelectRow of SummaryListViewController which will update the UI elements according to the data i send.
I have tried the following things to achieve this,
I tried using addObserver in NotificationCenter. When i click on the list, i added an observer. And this observer triggers the method in the detailViewController that will update the UI elements. But this doesn't work well all the time. When i come to Summary page, go back and if i come again to summary page and do the same, the observer is called twice even after removing the observer in ViewDidDisapper. And also i learnt in few websites that NotificationCenter should not be used for this kind of a situation.
Second, Am trying to use protocols. I thought i would write a protocol in the SummaryListViewController
protocol SummaryDetailProtocol {
func setSummaryDetails()
}
class SummaryListViewController: UIViewController
{
var summaryDetailsDelegate : SummaryDetailProtocol?
func delegateFromSummaryDetails(delegate: SummaryDetailProtocol)
{
self.summaryDetailsDelegate = delegate
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
self.summaryDetailsDelegate?.setSummaryDetails()
}
func delegateFromSummaryDetails(delegate: SummaryDetailProtocol)
{
self.summaryDetailsDelegate = delegate
}
}
Now in the ViewDidLoad of the SummaryDetailViewController, I would like to send the reference of the delegate to the listViewController so that the listViewController can call the setSummaryDetails method.
override func viewDidLoad()
{
super.viewDidLoad()
sendDelegateReferenceToListPage()
}
func sendDelegateReferenceToListPage()
{
let summaryListObj = SummaryListView()
//This is where the error occurs. It throws the error since i try to cast SummaryDetailViewController to parameter of type SummaryDetailProtocol of SummaryListViewController
summaryListObj.delegateFromSummaryDetails(delegate: self as! SummaryDetailProtocol)
}
Can anyone help me to get out of this
Protocol solution is the best. You can use like this
SummaryListViewController file:
protocol SummaryDetailProtocol {
func setSummaryDetails()
}
class SummaryListViewController: UIViewController
{
var summaryDetailsDelegate : SummaryDetailProtocol?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
self.summaryDetailsDelegate?.setSummaryDetails()//use here
}
}
SummaryDetailViewController file:
class SummaryDetailViewController: UIViewController,SummaryDetailProtocol
{
internal func setSummaryDetails() {
//return whatever you want
}
}
And finally set SummaryListViewController delegate to SummaryDetailViewController:
let detailViewController = SummaryDetailViewController(nibName: (UIDevice.current.userInterfaceIdiom == .pad ? "SummaryDetailViewController" : "SummaryDetailViewController_iPhone"), bundle: nil)
addChildViewController(detailViewController)
DetailView.frame = CGRect(x: DetailView.frame.origin.x, y: DetailView.frame.origin.y, width: self.DetailView.frame.size.width, height: self.DetailView.frame.size.height)
DetailView.addSubview(detailViewController.view)
detailViewController.didMove(toParentViewController: self)
let listViewController = SummaryListViewController(nibName:"SummaryListViewController", bundle: nil)
addChildViewController(listViewController)
listViewController.view.frame = CGRect(x: 0, y: 0, width: self.ListView.frame.size.width, height: self.ListView.frame.size.height)
ListView.addSubview(listViewController.view)
listViewController.didMove(toParentViewController: self)
listViewController.summaryDetailsDelegate = detailViewController // set delegate detail view controller
Related
I have a segue named "hydrogenSegue" from a "hydrogenBoxButton" to a "Hydrogen" view controller. However, I also wanted to implement a table view so I could search for an element. I tried to make the code so when the cell is clicked it will segue over to the element's view. I used hydrogen as an example here.
In my main ViewController.swift file, I have this to transfer the data:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//If identifier equals the hydrogen element go to the elements Swift file
if segue.identifier == "hydrogenSegue" {
let hydrogenAtomicNumberPassing = segue.destination as! hydrogenViewController
hydrogenAtomicNumberPassing.hydrogenAtomicNumberPassed = hydrogenAtomicNumber
let hydrogenAtomicMassPassing = segue.destination as! hydrogenViewController
hydrogenAtomicMassPassing.hydrogenAtomicMassPassed = hydrogenAtomicMass
}
}
In the hydrogenViewController.swift file I have this:
import UIKit
class hydrogenViewController: UIViewController {
var hydrogenAtomicNumberPassed: Int!
var hydrogenAtomicMassPassed: Float!
#IBOutlet weak var hydrogenInformationLabel: UILabel!
#IBOutlet weak var hydrogenAtomicNumberLabel: UILabel!
#IBOutlet weak var hydrogenAtomicMassLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
//Setting the background color
self.view.backgroundColor = UIColor.gray
//Converting hydrogen's atomic number from an Int to a String
let hydrogenAtomicNumberString = String("\(hydrogenAtomicNumberPassed!)")
hydrogenAtomicNumberLabel.text = "Atomic Number: \(hydrogenAtomicNumberString)"
//Converting hydrogen's atomic mass from a Float to a String
let hydrogenAtomicMassString = String("\(hydrogenAtomicMassPassed!)")
hydrogenAtomicMassLabel.text = "Atomic Mass: \(hydrogenAtomicMassString)"
}
}
I am getting the error at:
let hydrogenAtomicNumberString = String("\(hydrogenAtomicNumberPassed!)")
I'm assuming it would happen to this line also if I fix only that line:
let hydrogenAtomicMassString = String("\(hydrogenAtomicMassPassed!)")
I have this code in my "searchViewController" (the .swift file used for the table view):
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("row selected : \(indexPath.row)")
if indexPath.row == 0 {
let hydrogenSearchSegue = UIStoryboard(name:"Main",
bundle:nil).instantiateViewController(withIdentifier: "hydrogenView") as!
hydrogenViewController
self.navigationController?.pushViewController(hydrogenSearchSegue,
animated:true)
}
}
When I click on the "Hydrogen" cell in the table view it crashes to this error:
Hydrogen cell
The crash
When I click on the "H" button in this image it will take me to the hydrogen view controller:
Image of the Hydrogen Button in the simulator (Top Left)
Image of the Hydrogen View Controller
I want the hydrogen cell to segue over to the hydrogen view controller just like the button can.
When this same issue came up earlier I just had an issue with the name of the segue in the storyboard. However, because there is no visible segue from the table view, I don't know how to fix the issue.
I've tried this:
performSegue(withIdentifier: "hydrogenSegue", sender: nil)
I was thinking that I could just reuse the "hydrogenSegue" from the button to the view controller but I get a SIGABRT error. It just says that there is no segue with the name "hydrogenSegue." It would be best if I could just reuse that segue in a way because everything is already connected but I now found out that the "searchViewController" can't recognize the segue. Any help is appreciated and my main goal is to just get the cell that is clicked on to move over to the element's designated view. I tried to provide as much information as possible without making it to long and if there is any more information needed, I should be able to provide it.
well. first answer
in your hydrogenViewController try with this lines.
var hydrogenAtomicNumberPassed: Int?
var hydrogenAtomicMassPassed: Float?
override func viewDidLoad(){
super.viewDidLoad()
self.viewBackgroundColor = .gray
}
override func viewWillAppear(){
super.viewWillAppear()
if let number = hydrogenAtomicNumberPassed
{
hydrogenAtomicNumberLabel.text = "Atomic Number: \(number)"
}
if let mass = hydrogenAtomicMassPassed
{
hydrogenAtomicMassLabel.text = "Atomic Mass: \(mass)"
}
}
Now, the segues only "lives" between a couple viewControllers, if you have a third view controller, the last will not recognize him.
other thing, you are using segues and navigation controller, from my point of view, it's a bad idea mixed both, I mean, there are specific apps that can use both ways to present views, only is a advice.
if you want to pass data with pushviewcontroller only use this line
if indexPath.row == 0 {
let hydrogenSearchSegue = UIStoryboard(name:"Main",bundle:nil).instantiateViewController(withIdentifier: "hydrogenView") as! hydrogenViewController
hydrogenSearchSegue.VAR_hydrogenViewController = YOURVAR_INYOURFILE
self.navigationController?.pushViewController(hydrogenSearchSegue, animated:true)
}
tell me if you have doubts, and I will try to help you.
I have tried looking at answers on similar questions to this, but I am not particularly experienced and have had trouble following them, so any help would be much appreciated! My situation is as follows: when I press a button in my Parent ViewController, the following code is used to call a Child ViewController (by the way, the Child is actually a TableViewController, but it seems to work fine "thinking" it's a normal ViewController?):
controller = (storyboard?.instantiateViewController(withIdentifier: "People"))
addChildViewController(controller!)
controller?.view.frame = CGRect(x: 10, y: 200, width: 394, height: 300)
self.view.addSubview((controller?.view)!)
controller?.didMove(toParentViewController: self)
What I would then like is to transfer an array from the Parent to the Child, where it will be used as the TableView's data?
Secondly, when I select a cell from the Child's TableView, I would like the relevant information to be sent to the Parent, and for the Child to disappear.
In case it is of interest, I have managed to close the Child under different circumstances (when a click occurs in the Parent while the Child is displayed) using the following:
controller?.willMove(toParentViewController: nil)
controller?.view.removeFromSuperview()
controller?.removeFromParentViewController()
I would really appreciate any advice, even if it's a link to something which would help!
You can pass value from Parent to Child Controller like this
controller = (storyboard?.instantiateViewController(withIdentifier: "People"))
addChildViewController(controller!)
controller?.view.frame = CGRect(x: 10, y: 200, width: 394, height: 300)
controller.tableDataSource = // Pass your required value to child controller
self.view.addSubview((controller?.view)!)
controller?.didMove(toParentViewController: self)
Now you want to transfer back your select value to Parent view controller. For this purpose your have a create a Delegate in ChildController like
#protocol ChildControllerDelegate : class {
func selectedValue(Value : String)
}
After that make a variable of that delegate in ChildController like this
weak var delegate : ChildControllerDelegate?
and when in rowDidSelect method add following code
if(delegate != nil) {
delegate.selectedValue(Value :"Your selected value")
}
Now step when you are going to show ChildController from ParentController at that time you have to set that delegate object to ParentController like this
controller = (storyboard?.instantiateViewController(withIdentifier: "People"))
addChildViewController(controller!)
controller?.view.frame = CGRect(x: 10, y: 200, width: 394, height: 300)
controller.delegate = self
self.view.addSubview((controller?.view)!)
controller?.didMove(toParentViewController: self)
and after that just implement the delegate method in ParentController like that
func selectedValue(Value : String) {
// you select val
}
Try This.
First Create Public Method For Add And Remove childVC.
For Add childVC.
public class func openChildViewController(parentVC:UIViewController, with childVC:UIViewController){
parentVC.addChildViewController(childVC)
childVC.view.frame = parentVC.view.frame
parentVC.view.addSubview(childVC.view)
parentVC.didMove(toParentViewController: childVC)
}
For Remove childVC.
public class func removeChildViewController(childVC:UIViewController){
childVC.willMove(toParentViewController: nil)
childVC.view.removeFromSuperview()
childVC.removeFromParentViewController()
}
Use Above Method.
1.ParentVC.swift
class ParentVC: UIViewController , ChildVCDelegate {
var arrType = NSMutableArray()
//add ChildVC
#IBAction func btnAddChildVC(_ sender: UIButton) {
let ChildVC = self.storyboard?.instantiateViewController(withIdentifier: "ChildVC") as! ChildVC
PickerVC.arrPass = arrType //for data passing create any object in ChildVC for ex. arrPass is NSMutableArray
ChildVC.delegate = self
openChildViewController(parentVC: self, with: ChildVC)
}
// MARK: ChildVC Delegate
func SetSelectedPickerValue(strSelectOption: String) {
print(strSelectOption)
}
}
}
2.ChildVC.swift
class ChildVC: UIViewController{
// MARK: Variable for ParentVCData Passing
var arrPass = NSMutableArray()
override func viewWillAppear(_ animated: Bool) {
print(arrPass)
}
//Remove ChildVC
#IBAction func btnRemoveChildVC(_ sender: UIButton) {
self.delegate?.SetSelectedPickerValue!(strSelectOption: “any String you pass ChildVC To ParentVC”)
removeChildViewController(childVC: self)
}
}
// MARK: Create Delegate Method
#objc protocol ChildVCDelegate{
#objc optional func SetSelectedPickerValue(strSelectOption:String)
}
You can:
Cast the controller to the appropriate class for the child view controller (I'm using ChildViewController below, but hopefully you have a more descriptive name); and
Pass the array (which I guessed you might have called people, but use whatever your array names are in these two respective view controllers) from the current view controller (the parent) to this new child view controller.
Thus:
let child = storyboard!.instantiateViewController(withIdentifier: "People") as! ChildViewController
addChildViewController(child)
child.people = people
child.view.frame = ...
view.addSubview(child.view)
child.didMove(toParentViewController: self)
Personally, I wouldn't hard code the child coordinates like you did in your original question. I'd set translatesAutoresizingMaskIntoConstraints to false and then add the appropriate leading/trailing/top/bottom constraints, but that's up to you. It was just too painful to see hardcoded coordinates in your example.
I got UINavigationController inside my app with a rootVC "VC1", VC1 containts a collectionview with 2images inside every cell. When user select cell, navigationcontroller will pass images from cell to new vc "VC2" and then push it to the top of navigationcontroller. My problem is when I take down VC2 via popviewcontroller, VC2 is deallocated correctly but memory stays at the same higher level (after pushing new vc it increases from 60mb to 130mb). I've trying set image to nil, and imageview also but none of this work. Here's some of my code:
class VC1: UIViewController {
var selectedUserPollDetails : VC2?
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! AppUserCell
selectedUserPollDetails = VC2()
selectedUserPollDetails?.leftPhoto = cell.leftImageNode.image
selectedUserPollDetails?.rightPhoto = cell.rightImageNode.image
navigationController?.pushViewController(selectedUserPollDetails !, animated: true)
}
}
class VC2: UIViewController {
lazy var arrow : ArrowBack = {
let arrow = ArrowBack()
return arrow
}()
weak var leftPhoto: UIImage?
weak var rightPhoto: UIImage?
var leftPhotoImageview: UIImageView = {
let imageview = UIImageView()
imageview.contentMode = .scaleAspectFill
imageview.layer.cornerRadius = 5
imageview.layer.masksToBounds = true
return imageview
}()
var rightPhotoImageview: UIImageView = {
let imageview = UIImageView()
imageview.contentMode = .scaleAspectFit
imageview.layer.cornerRadius = 5
imageview.clipsToBounds = true
return imageview
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(leftPhotoImageview)
view.addSubview(rightPhotoImageview)
view.addSubview(arrow)
arrow.addTarget(self, action: #selector(handleArrowBack), for: .touchUpInside)
}
func handleArrowBack(){
navigationController?.popViewController(animated: true)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
leftPhotoImageview.frame = CGRect(x: 100, y: 0, width: 100, height: 100)
rightPhotoImageview.frame = CGRect(x: 100, y: 200, width: 100, height: 100)
if leftPhoto != nil, rightPhoto != nil{
leftPhotoImageview.image = leftPhoto
rightPhotoImageview.image = rightPhoto
}
}
deinit{
leftPhoto = nil
rightPhoto = nil
leftPhotoImageview.image = nil
rightPhotoImageview.image = nil
}
I've even added deinit at the end to make sure photos are deallocated. So basically when i'm trying to push VC2 again (after pop) amount of memory is doubled again (260mb) and so on... what causing this problem? what am i doing wrong?
btw. i've omitted less important func and vars
You defo have a memory leak. I believe everytime
you push a new view via the nav controller it creates a brand new view i.e. the view is completely new and isn't reused. If you have strong references within the view you've pushed to they won't be released unless you deinit as they have a strong ref to view you've pushed so they linger around. You mentioned you deinit those items. Have you also tried marking leftPhotoImageView and rightPhotoImageView also as weak properties? Something is holding onto those images it would seem.
You could also change deinit to leftPhotoImageview = nil and rightPhotoImageView = nil rather than setting the imageview.image property to nil if that makes sense.
Ok, i think i found a solution, i don't know why i haven't trying this one, so i marked my imageview as lazy, and now memory is decreasing after popping vc
I have a custom view that loads from a nib file. This view has a custom delegate, I set the delegate to my main view controller but then at some point the delegate gets set to nil again.
here is I add the custom view to my view controller
#IBAction func newGoalButtonTapped(_ sender: UIBarButtonItem) {
let newGoalView = AddGoalView(frame: self.view.frame)
newGoalView.delegate = self
self.view.addSubview(newGoalView)
newGoalView.present()
}
Here is how I load the nib file in my custom view init method
override init(frame: CGRect) {
super.init(frame:CGRect(x: frame.origin.x + 10, y: frame.height, width: frame.width - 20, height: frame.height / 3))
self.addSubview(self.instanceFromNib())
}
private func instanceFromNib() -> AddGoalView {
return UINib(nibName: "AddGoalView", bundle: nil).instantiate(withOwner: self, options: nil)[0] as! AddGoalView
}
and this is how I declare my protocol
protocol NewGoalCreatedDelegate {
func newGoalCreated(with proteinGoal:Int16, isCurrent:Bool)}
I set the files owner of my nib file to my custom class "AddGoalView", and also the view custom class to "AddGoalView". I also tried one or the other but no luck.
The delegate isnt nil until after my present method.
internal func present() {
UIView.animate(withDuration: 0.3, animations: {
self.center = self.superview!.center
}, completion: {(finished:Bool) in
print(self.delegate!)
})
print(self.delegate!)
}
After that the delegate is nil, I know it is something related to how Im using my nib file but I dont know what it is.
I forgot to link the outlets in the file's owner, to the views of my xib.file
.
I'd like to use an instance of a separate class as my UITableView's datasource & delegate. I create a new instance of the class that should handle this role and assign it via my tableview's properties:
autoMakesTable is defined as property:
var autoMakesTable : UITableView?
Further down:
func nextBttnTouched(sender: AnyObject) {
switch self.autoState {
case .NewOrEdit:
self.autoState = .YearEntered
// If the picker wasn't used create a new Auto with the default year value
self.auto = Auto(year: NSNumber(integerLiteral: self.yearPickerValues.count - 2), make: "", model: "", body: "", trim: "", downPaymentBudget: 0, monthlyPaymentBudget: 0)
// Prepare the make & model fields
backgroundFieldView = UIView(frame: CGRectMake(0, 0-self.view.frame.size.height/2, self.view.frame.width, self.view.frame.height/2))
backgroundFieldView!.backgroundColor = UIColor(red: 251/255, green: 251/255, blue: 251/255, alpha: 1.0)
let makeField = UITextField(frame: CGRectMake(self.view.center.x - 100, self.navigationController!.navigationBar.frame.size.height + 34, 200, 30))
makeField.delegate = self
makeField.placeholder = "Make"
makeField.addTarget(self, action: Selector("makeTextChanged:"), forControlEvents: UIControlEvents.EditingChanged)
let modelField = UITextField(frame: CGRectMake(self.view.center.x - 100, makeField.frame.origin.y + makeField.frame.size.height + 8, 200, 30))
modelField.placeholder = "Model"
let newAutoMakesTableData = AutoMakesTableData()
autoMakesTable = UITableView(frame: CGRectMake(makeField.frame.origin.x, makeField.frame.origin.y + makeField.frame.height + 2, makeField.frame.width, 100))
autoMakesTable!.dataSource = newAutoMakesTableData
autoMakesTable!.delegate = newAutoMakesTableData
self.backgroundFieldView?.addSubview(self.autoMakesTable!)
self.autoMakesTable!.reloadData()
makeField.becomeFirstResponder()
self.addBorderToTextField([makeField,modelField])
self.view.addSubview(backgroundFieldView!)
// Move year picker with animation
// Update next button location while loading make / model input fields with animation
UIView.animateWithDuration(0.8, animations: { () -> Void in
self.newYearPicker?.frame.origin.y = 0
self.backgroundFieldView!.frame.origin.y = 0
self.backgroundFieldView!.addSubview(makeField)
self.backgroundFieldView?.addSubview(modelField)
//self.backgroundFieldView?.addSubview(self.autoMakesTable!)
// self.autoMakesTable!.reloadData()
})
case .YearEntered:
self.autoState = .MakeModelEntered
case .MakeModelEntered:
self.autoState = .DetailsEntered
case .DetailsEntered:
self.autoState = .BudgetEntered
case .BudgetEntered:
performSegueWithIdentifier("next", sender: self)
}
}
It's added onto the view hierarchy (I intact see an empty tableview with a few rows) later on. I also try to call reloadData() on it to no effect.
AutoMakesTableData is defined like so:
import UIKit
class AutoMakesTableData: NSObject, UITableViewDataSource, UITableViewDelegate {
// Auto makes URL
// This should be hosted online so changes can be made w/out having to re-submit the app
let urlForMakes = NSBundle.mainBundle().URLForResource("makes", withExtension: "JSON")
var autoMakes : [String]?
override init() {
super.init()
self.populateAutoMakesFromURL(urlForMakes!)
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let aCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
print("cell created")
return aCell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("selected row")
}
private func populateAutoMakesFromURL(url: NSURL) {
do {
let jsonAutoMakesData = try NSData(contentsOfURL: url, options: NSDataReadingOptions.DataReadingMappedIfSafe)
do {
let jsonAutoMakes = try NSJSONSerialization.JSONObjectWithData(jsonAutoMakesData, options: NSJSONReadingOptions.MutableContainers) as! [String:[String]]
self.autoMakes = jsonAutoMakes["makes"]
// Sort array alphabetically
self.autoMakes?.sortInPlace(<)
} catch let error as NSError {
print(error.userInfo.debugDescription)
}
} catch let error as NSError {
print(error.userInfo.debugDescription)
}
}
}
I can access the autoMakes array property on this instance without a problem.
The table view shows up but none of the print statements fire (for a cell at index path or for did select row).
I don't see anywhere where you install the table view into the view hierarchy. If you don't install the view controller into the active view hierarchy it won't do anything.
That is my guess as to what's going wrong.
It's ok to have a separate object serve as the data source/delegate of the view controller.
EDIT:
Based on discussion below this answer, it turns out the problem was that the OP was creating his AutoMakesTableData in a method and assigning it to a local variable but not saving any other strong references to it.
When the method that created the AutoMakesTableData object returned, the local variable went out of scope, there were no more strong references to the object, and it was deallocated.
A table view's delegate and dataSource properties are weak, so those get zeroed out when the object is deallocated. The table view no longer has a data source, so nothing happens.