View Controller doesn't dealloc when perform segue - ios

I have a problem in my apps that its memory increase constantly. So here is my app structure. I am using SWrevealViewController for slidemenu.
Slidemenu
- View Controller A
- View Controller B
- View Controller C
My View Controller A consist of UICollectionView and ScrollView.
When I perform segue from View Controller A to View Controller B, the memory is doing fine. But if I am going to View Controller A with slide menu, the memory increases.
Here is my didSelectRowAtIndexPath on SWRevealViewController's table delegate. I am using performSegueWithIdentifier
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if isLoggedIn {
self.performSegueWithIdentifier(idSegueLoggedIn[indexPath.row], sender: self)
}
}
Then I am going to View Controller B via slide menu and then going to View Controller A again, on that point memory increases constantly.
It looks like my View Controller A that consist of UICollectionView doesn't release its object on memory. But if I remove my UICollectionView, my memory issue was dissapear and it runs well.
So I think it was about my reference to UICollectionView. I already declared that with weak property but it does nothing.
#IBOutlet weak var othersCollectionView: UICollectionView!
I try to called deinit() in my View Controlle A but it doesn't called.
Here is my memory usage graph, on each "black arrow", I move to View Controller A with slide menu.
Pls let me know if I am doing something wrong. Thank you so much.

I am answering a bit late but I had a similar problem. I the end my problem was linked to the declaration of delegates in some UITableViewCell. I fixed the problem by declaring the delegate variable as weak.
Here is an example :
class MyTableViewCell: UITableViewCell {
#IBOutlet weak var myNameTextField: UITextField!
weak var delegate: CellDbErrorDelegate?

Related

Swift: UIControl in TableViewController found nil when called by ViewController

I have two viewControllers in the storyboard, a ViewController (root) and a TableViewController, that are linked by a push segue.
The TableViewController acts as a setting page of the app and multiple UIControls such as UISegmentedControl and UISwitch are put in it. These UIControls are linked to the TableViewController via IBOutlets.
#IBOutlet weak var mySegmentedControl: UISegmentedControl!
#IBOutlet weak var mySwitch: UISwitch!
However, when I call these UIControls in the ViewController by:
let tableView: TableViewController = TableViewController.init(nibName: nil, bundle: nil)
if tableView.mySwitch.isOn {
//perform actions
}
Error pops up at the if-statment:
fatal error: unexpectedly found nil while unwrapping an Optional value
I thought it was because the TableViewController has not been loaded when the UIControls are being called, thus I have tried calling the viewDidLoad() of tableView first, but the error still remains.
What should I do? Appreciate any suggestions.
You do not directly call viewDidLoad, this is done by UIKit after the view is being loaded. And the view is loaded when the view needs to be displayed.
If you need to access the outlets before, you can force loading by
tableView.loadViewIfNeeded()
But remember:
Maybe it's better to do the outlet stuff inside viewDidLoad of the involved controller, and not from outside.
You should not name the controller variable tableView. That name suggest to be a view and not a controller. Better name it tableViewCtrl or so.

Setting up a ViewController for a .xib view

I am neither an iOS developer, nor a swift developer, but please bear with me:
I am currently trying to implement a simple iOS app but I have difficulties understanding how exactly I am supposed to set up custom UIViews and ViewControllers for those UIViews.
I am using a UIScrollView that is containing items a little bit more complex than just images, thats what I use custom views for.
What I did was:
I created a .xib file, the view itself. I added some elements (here it is only a textfield, for simplicity's sake).
I created a cocoa touch class "CustomView" that inherits from UIView and set my view up to be of that class (inside the class I just set up elements and such).
Now I want a ViewController that controls the class whenever it is rendered (for example reacting to the changing textField).
I cant manage everything from my main ViewController, because it would get too big (e.g. 3 scrollViews * 5 subviews that need to be managed).
I want a solution that uses ViewControllers for each subview (in case they themselves will have subviews, too).
How do I do that?
Do I need to add some sort of childViewController?
I really am at loss, most of the blog posts and SO examples simply do not work and/or are outdated and I am unsure about whether or not I got the whole View - ViewController pattern wrong.
Let's say you have two view controllers, MainViewController and TableViewController. TableVC's main view is to be a subview of MainVC's main view. In addition, you wish to pass back to MainVC which cell was selected in TableVC.
A solution is (a) make TableVC be a child to MainVC and (b) make MainVC be a delegate for TableVC.
TableViewController:
protocol TableVCDelegate {
func cellSelected(sender: TableViewController)
}
class TableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
// please note that you can do delegation differently,
// this way results in crashes if delegate is nil!
var delegate:TableVCDelegate! = nil
var someValue = ""
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// set someValue to contents in the selected cell or it's data source
someValue = "Hello World!"
delegate.cellSelected(sender: self)
}
}
MainViewController:
class MainViewController: UIViewController, TableVCDelegate {
let tableVC = TableViewController()
override func viewDidLoad() {
// make tableVC be a child of this VC
addChild(tableVC)
tableVC.didMove(toParent: self)
tableVC.delegate = self
// position tableVC.view
tableVC.view.translatesAutoresizingMaskIntoConstraints = false
}
func cellSelected(sender: TableViewController) {
print(sender.someValue) // this should send "Hello World!" to the console
}
}
This is obviously untested code, but it is based on product code. This is meant to be a shell to help you get started.

Exchange Date between UITableViewController and ContentViewController with multiple pages

I am working on an application where I need to pass an array of values from a click of tableview cell in my tableviewcontroller which is the initial view controller to a contentview view controller with page curl transition.
Each of the page will have a textview which will be populated with value passed from the initial view controller and can be edited by the user.
My issue is, I am not able to update the array with the new value and pass it back to the initial view controller
I tried the following:
I implemented pageviewcontroller methods in my initialview controller to create instances of the ContentViewController with page curl transition and was able to pass values to each of the pages when the page curl was done. But I am trying to figure out a way to pass back the updated value to the tableviewcontroller from where I instantiated the object.
I tried Segue from tableview to the contentViewcontroller, but it does not work.
Appreciate if somebody can help me.
Use the delegate pattern.
Define a protocol within ContentViewController :
protocol UpdateModelDelegate {
func didDismissContentViewController(controller:ContentViewController)
}
Establish a delegate variable within ContentViewController :
var delegate: UpdateModelDelegate?
When you dismiss ContentViewController call delegate?.didDismissContentViewController(self) which will send the data back to your UITableViewController.
Have the UITableViewController conform to this protocol.
class MyTableViewControllerSubclass: UITableviewController, UpdateModelDelegate
When presenting the ContentViewController set your UITableViewSubclass as the delegate.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var contentViewController: ContentViewController()
//After you pass the necessary data to contentViewController...
contentViewController.delegate? = self
}
finally, implement the delegate function within your UITableviewController subclass.
func didDismissContentViewController(controller:ContentViewController) {
//You're passed in the contentViewController here, use relevant data to update your model.
}

Change value / image in view controller by selecting a cell within a collection view within an embedded container

In a detail view controller, I've a 'featureImage' in the top left, and a thin horizontal strip of images below this. The strip of images is an embedded container view managed by a custom CollectionViewController, which shows an array of images. The initial featureImage is the first image in an array of images[0], and the same array is passed to the collection view.
I'd like the featureImage to update to the same image if a cell in the container view is selected / tapped.
I guess I need to call the delegate method didSelectItemAtIndexPath, which will give me the indexPath. Right? But then how do I pass the indexPath, which is already from a delegate, back to the detail view controller.
EDITED - The code shows code overlap and differences between Responder Chain AND delegate approaches. Uncommented in the didSelectItemAtIndex path, the Responder Chain approach works, while the delegate approach does not.
Protocol defined and included at top of DetailViewController (I doesn't seem to matter which file the protocol is in, and is only typed to class to allow the delegate property to be 'weak'). Needed for both approaches.
protocol FeatureImageController: class {
func featureImageSelected(indexPath: NSIndexPath)
}
class DetailViewController: UIViewController, FeatureImageController {
Delegate property declared in the custom UICollectionViewController class. Only needed for delegate approach.
weak var delegate: FeatureImageController?
Delegate property initiated in the DetailViewController. Only needed for delegate approach.
override func viewDidLoad() {
super.viewDidLoad()
let photoCollectionVC = PhotoCollectionVC()
photoCollectionVC.delegate = self as FeatureImageController ... }
The Responder Chain (active) OR the delegate approach (commented out) within the collection view controllers didSelectItemAtIndexPath method.
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
{
if let imageSelector = targetForAction("featureImageSelected:", withSender: self) as? FeatureImageController {
imageSelector.featureImageSelected(indexPath)
}
// self.delegate?.featureImageSelected(indexPath)
}
Delegate method in DetailViewController. Needed for both.
func featureImageSelected(indexPath: NSIndexPath) {
record?.featureImage = record?.images[indexPath.row]
self.configureView()
}
The communication of data selection between View Controllers in my experience can best be achieved in two ways- the delegation or responder chain route. Either way the first step would be creating a protocol that your DetailViewController will adhere to. Something like:
protocol FeatureImageController: class {
func featureImageSelected(image: UIImage)
}
Your DetailViewController would then implement this function and use it to change the 'feature image'. How this is communicated then depends on whether you use delegation or the responder chain.
Delegation
If you prefer to use delegation then declare a delegate property on your CollectionViewController like so:
weak var delegate: FeatureImageController?
then in didSelectItemAtIndexPath you would determine the selected image using the provided indexPath and pass it to your delegate:
delegate?.featureImageSelected(selectedImage)
where selectedImage is the image selected from the collection view.
Responder Chain
If you decide to use the responder chain then you need not declare a delegate property. Instead you would ask for the first target that responds to your protocol method. So inside didSelectItemAtIndexPath you would say:
if let imageController = targetForAction("featureImageSelected:", withSender: self) as? FeatureImageController {
imageController.featureImageSelected(selectedImage)
}
Both methods (delegation or responder chain) allow the collection view controller to pass its selection to the detail controller. The delegation route is more common in the Framework but I find as we use containers within containers more often it becomes pretty nasty to properly manage the chain of delegates without an amount of 'coupling' I'm not comfortable with. The responder chain, on the other hand, is already provided by the framework to 'dig' into the hierarchy of controllers to find one willing to handle your action.

outlets in UIViewController nil in viewdidload

I have a UIViewController with an outlet for a tableView
#IBOutlet weak var tableView: UITableView!
When I try to access the tableView variable in viewDidload it's throwing an error saying tableView is nil.
Everything seems to be set up in the interface builder. The class for File's Owner is set to my custom class and the tableView outlet is set as well. What could be going wrong here, why is tableView variable still nil even inside viewDidLoad?
Did you type out that outlet code without creating a link?
If you did that would be your problem.
Go back to your Storyboard, switch to assistant editor mode and CTRL + Drag from the UITableView to #IBOutlet weak var tableView: UITableView!
Ensure you're got a FILLED IN circle to the left of your var similar to this.

Resources