passing in custom class as arg in init - ios

I'm trying to pass in a custom object to populate my view
class ViewController : UIViewController {
convenience init() {
self.init(data: CustomObject) <----- Error: Cannot convert value of type 'CustomObject.Type' to expected argument type CustomObject
}
init (data: CustomObject) {
self.data = data
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Usually if I'm passing in an array I just pass in an empty array like below
convenience init() {
self.init(data: [])
}
init (data: Array<String>) {
self.data = data
super.init(nibName: nil, bundle: nil)
}
But since I'm passing in a custom object I'm not sure what to place there

You are currently passing the type, not an actual object of that type. Assuming your CustomObject has a initializer without any arguments use:
convenience init() {
self.init(data: CustomObject()) // create an instance and pass it along
}

Related

How to write custom UIViewController initialiser with property in Swift?

I am trying to write my own UIVC initializer:
let person: Person
init(withPerson person: Person) {
self.person = person
super.init()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
but in my coordinator I have this line:
func getViewController() -> UIViewController? {
return ViewController(nibName: "ViewController", bundle: Bundle.main)
}
and it causes a crash with error:
Fatal error: Use of unimplemented initializer 'init(nibName:bundle:)' for class 'ViewController'
when I try to add:
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
it rises an error with:
Property 'self.person' not initialized at super.init call
is there a way how I can fix the crash?
init(withPerson person: Person) {
self.person = person
super.init (nibName: "ViewController", bundle: Bundle.main)
}
You have to call super.init(nibName:bundle:) instead of super.init() as it's a designated initializer.
If you specify nil for the nibName parameter and you do not override the loadView() method, the view controller searches for a nib file as described here.
init(withPerson person: Person) {
self.person = person
super.init(nibName: nil, bundle: nil)
}

UIViewController with closure init

I try to create UIViewController:
class CategoriesVC: UIViewController {
let tableView = UITableView()
var completionHandler: (Category)->Void?
init(completionHandler: #escaping (Category)->Void) {
super.init()
self.completionHandler = completionHandler
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
and I get this error:
Must call a designated initializer of the superclass 'UIViewController'
On this line:
super.init()
The error states clearly that you must call the designate init for UIViewController, which in this case is super.init(nibName:,bundle:).
Also, the completionHandler syntax is wrong, here's the fix:
class CategoriesVC: UIViewController {
let tableView = UITableView()
var completionHandler: ((Category)->Void)?
init(completionHandler: #escaping ((Category)->Void)) {
super.init(nibName: nil, bundle: nil)
self.completionHandler = completionHandler
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

Why passed value is nil in viewcontroller

I know this is simple question but I couldn't understand for hours what's the problem here.
enum TypeOfAlert {
case success, error, warning, confirm
}
class MainAlertView: UIViewController {
var mode: TypeOfAlert!
var transitioner : CAVTransitioner
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
self.transitioner = CAVTransitioner()
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
self.modalPresentationStyle = .custom
self.transitioningDelegate = self.transitioner
setupAlertView()
}
private func setupAlertView() {
print(mode) // result is nil
}
convenience init() {
self.init(nibName:nil, bundle:nil)
}
required init?(coder: NSCoder) {
fatalError("NSCoding not supported")
}
}
I have this code to show alertdialog
I opening MainAlertView by pressing a button
let vc = IFOMainAlertView()
vc.delegate = self
vc.mode = TypeOfAlert.confirm
self.present(vc,animated: true)
but when I am printing or debuging var mode is always nil. Why ?
You have printed var mode before you set it
you are trying to debug at initialisation moment,
when you called
let vc = IFOMainAlertView()
the function init was called, before you called the rest:
vc.delegate = self
vc.mode = TypeOfAlert.confirm
either add a new constructor to your class that takes mode as an argument, or delay debugging the mode attribute to the viewDidLoad method

How to send a complete closure better

What I want is to send a closures to a UIViewController to tell it what it will do in the end. But when it comes to a package of UIViewControllers it will be a little messy.
class ViewController: UIViewController {
private var complete: ()->()
init(complete: ()->()){
self.complete = complete
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class ViewController2: UIViewController {
private var complete: ()->()
init(complete: ()->()){
self.complete = complete
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Here are my UIViewControllers. What want to do is to send a complete closure to UIViewController2, but I have to push UIViewController first. So what I have to do is send the closure to UIViewController, then UIViewController send the closure to UIViewController2. It is not messy when there are only two UIViewControllers. But it will be very messy when there comes out a package of UIViewControllers.
Any better solutions?
You the following code to handle the completion handler
First, create a base class of UIViewController and define the completionHandler
import UIKit
public class MyController: UIViewController {
var completionHandler: ((Bool, String) -> Void)? // Bool and String are the return type, you can choose anything you want to return
public func onComplete(completion : ((Bool, String) -> Void)?)
{
self.completionHandler = completion
}
override public func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override public func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
In ViewController1, you need to call another ViewController like this
class ViewController: MyController {
// Initialization of view objects
override func viewDidLoad()
{
super.viewDidLoad()
//You are loading another ViewController from current ViewController
let controller2 = self.storyboard?.instantiateViewControllerWithIdentifier("controller2") as? MyController
controller2?.onComplete({ (finished, event) in
self.completionHandler?(finished, event)
})
}
//This is your button action or could be any event on which you will fire the completion handler
#IBAction func buttonTapped()
{
self.completionHandler(boolType, controllerName)
}
and where ever, you will create a new ViewController you will need to set its completionHandler by writing the line
controller2?.onComplete({ (finished, event) in
self.completionHandler?(finished, event)
})

Reload TableViewController from parent

I have a TableViewController, lets call it A, that is in a container view of another view controller, B. I need A to reload it's data when a value changes in B. I also need it to get this changed value from B. Any ideas?
Have you considered using notifications?
So, in B – I would do something like:
// ViewControllerB.swift
import UIKit
static let BChangedNotification = "ViewControllerBChanged"
class ViewControllerB: UIViewController {
//... truncated
func valueChanged(sender: AnyObject) {
let changedValue = ...
NSNotificationCenter.defaultCenter().postNotificationName(
BChangedNotification, object: changedValue)
}
//... truncated
}
Followed up with A looking something like this – where ValueType is simply the type of the value you mentioned:
import UIKit
class ViewControllerA: UITableViewController {
//... truncated
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
//...truncated
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "onBChangedNotification:",
name: BChangedNotification,
object: nil)
}
//... truncated
func onBChangedNotification(notification: NSNotification) {
if let newValue = notification.object as? ValueType {
//...truncated (do something with newValue)
self.reloadData()
}
}
}
Lastly – don't forget to remove the observer in A's deinit method:
import UIKit
class ViewControllerA: UITableViewController {
//... truncated
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
//... truncated
}

Resources