How to write custom UIViewController initialiser with property in Swift? - ios

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)
}

Related

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")
}
}

Instance of a class only returning nil

Fairly new to swift, and struggling with creating an instance of a class within another class. I'm firing a notification and then in my app delegate it responds by playing the music player and changing label in my viewController, but when it tries to change the label app crashes with error "Unexpectedly found nil while implicitly unwrapping an Optional value". I can get round it by adding a '?' but why is it getting nil.
Code
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, AVAudioPlayerDelegate {
var musicPlayerManager: MusicPlayerManager = MusicPlayerManager()
var viewController: ViewController = ViewController()
func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
//show an alert window
var playlistName: String = ""
if let userInfo = notification.userInfo {
playlistName = userInfo["soundName"] as! String
}
musicPlayerManager.playPlaylist(chosenPlaylist: playlistName)
print(playlistName)
viewController.currentPlaylist.text = "Playlist: \(playlistName)"
}
}
I'm getting the playlistName printed in the console, and then it crashes with the last line suggesting that it's an issue with the instance of viewController, and my attempt to change the label in the view controller from the app delegate.
Outlets are nil until vc loads also you need to load it from storyboard if it exists there
viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "id") as! ViewController
viewController.view.layoutIfNeeded()
viewController.currentPlaylist.text = "Playlist: \(playlistName)"
If you don't want to use storyboard you can create your ViewController in this structure. But you need to add your Subview(currentPlaylist) into your view and also need to set it's frame
import UIKit
class ViewController: UIViewController {
let currentPlaylist = UILabel()
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
init() {
super.init(nibName: nil, bundle: nil)
currentPlaylist.frame = CGRect(x: 0, y: 0, width: 200, height: 50)
view.addSubview(currentPlaylist)
}
}

passing in custom class as arg in init

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
}

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

MMDrawerController Subclass in Swift

if you're using Swift + CocoaPods + use_frameworks! with the MMDrawerController opened source (ObjC) library you might have trouble subclassing MMDrawerController getting multiple warnings of "unused initializer"
All you'll have to do is override the initializers and call super. Pretty easy but I saw that there was absolutely nothing on this issue while Googling for this issue, so I'm just trying to help out. I've posted my code below.
import UIKit
import MMDrawerController
class TRDrawerController: MMDrawerController {
private var recordsModel = TRRecordsModel.sharedInstanceOfRecordsModel
private var itemsModel = TRItemsModel.sharedInstanceOfItemsModel
init() {
let centerViewController = UIStoryboard(name: "TRMain", bundle: nil).instantiateViewControllerWithIdentifier("TRTrackerViewController") as! TRTrackerViewController
centerViewController.recordsModel = recordsModel
centerViewController.itemsModel = itemsModel
let firstNavigationController = TRNavigationController(rootViewController: centerViewController)
let rightViewController = UIStoryboard(name: "TRMain", bundle: nil).instantiateViewControllerWithIdentifier("TRSettingsViewController") as! TRSettingsViewController
rightViewController.recordsModel = recordsModel
centerViewController.itemsModel = itemsModel
let secondNavigationController = TRNavigationController(rootViewController: rightViewController)
super.init(centerViewController: firstNavigationController, leftDrawerViewController: nil, rightDrawerViewController: secondNavigationController)
self.openDrawerGestureModeMask = [.PanningCenterView]
self.closeDrawerGestureModeMask = [.PanningCenterView, .TapCenterView, .TapNavigationBar]
self.shouldStretchDrawer = false
}
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
// Won't be utilizing this, I want the app to crash if this gets used
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

Resources