Storyboard doesn't contain a controller with identifier 'PlannerViewController' - swift

I attached a PlannerViewController to my Main.storyboard. When I build and run the app, I get the following error :
Storyboard (<NSStoryboard: 0x608000001790>) doesn't contain a controller with identifier 'PlannerViewController'
In Main.storyboard, I did set PlannerViewController as the custom class and storyboard ID. Here's the code in PlannerViewController.swift :
import Cocoa
class PlannerViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
}
}
extension PlannerViewController {
// MARK: Storyboard instantiation
static func freshController() -> PlannerViewController {
let storyboard = NSStoryboard(name: "Main", bundle: nil)
guard let viewcontroller = storyboard.instantiateController(withIdentifier: "PlannerViewController") as? PlannerViewController else {
fatalError("Why cant i find QuotesViewController? - Check Main.storyboard")
}
return viewcontroller
}
}
Does anyone know how to solve this error ?
Please note that I'm using Swift 3, and that I'm new to Swift.
Thanks.
EDIT : By the way, I'm following this tutorial to develop a menu bar app.

You need to add id PlannerViewController here

Related

Swift: [NSNib _initWithNibNamed:bundle:options:] could not load the nibName

I am building a Cocoa app for production and when I create an NSViewController for routing without NSStoryboard instantiate, I got the error like below.
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[NSNib _initWithNibNamed:bundle:options:] could not load the nibName: ContentFully.AnotherController in bundle (null).
Actually I solved my problem via using an NSViewController to adding NSStoryboard but I would like to learn what is going on when I call it programmatically and why did crash?
Working scenario
let storyboard = NSStoryboard(name: "Dashboard", bundle: nil)
let vc = storyboard.instantiateInitialController() as! AnotherController
Crashed scenario
let vc = AnotherController()
self.view.window?.contentViewController = vc
Even if I create a class fully programmatically and non-relational with NSStoryboard I could not use it when I change the contentViewController. Is it necessary to search every controller in NSBundle for Swift?
Thanks in advance
A very simple working version would be:
import Cocoa
class AnotherController: NSViewController {
override func loadView() {
view = NSView(frame: NSMakeRect(0.0, 0.0, 400.0, 270.0))
let label = NSTextField(labelWithString: "Another Controller")
view.addSubview(label)
}
}
I can call that from my first controller using the code you say crashes and get the expected result.
#IBAction func replaceMe(_ sender: Any) {
let vc = AnotherController()
self.view.window?.contentViewController = vc
}

Quicklook always displays "no file to preview" error (url is valid)

I'm trying to use QuickLookController subclass as a child controller, setting its view as a subview in the parent. However, it always displays "no file to preview" message in the opening window. URL in the data source is valid, but the controller is never trying to get it! func previewItemAt index is never invoked!
func "numberOfPreviewItems" invokes always.
Please, help!
I get it. driven by example in article https://williamboles.me/hosting-viewcontrollers-in-cells/ I loaded my controller from bundle:
static func createFromStoryBoard() -> PreviewControler {
let storyboard = UIStoryboard(name: "PreviewControler", bundle: Bundle(for: PreviewControler.self))
guard let viewController = storyboard.instantiateViewController(withIdentifier: "PreviewControler") as? PreviewControler else {
fatalError("PreviewControler should be present in storyboard")
}
return viewController
}
But QuickLook controller must be created with it's constructor, so change to
let viewController = PreviewController()
solved the problem. Now all is fine.

Cannot convert value of type '(SwipeableTabBarController).Type' to expected argument type 'UIView'

I want to add Tabbar to my application. But when I try to add it, it gives the error in the header. How do I activate the Tabbar function?
public extension UIViewController {
public func setTabBarSwipe(enabled: Bool) {
if let swipeTabBarController = tabBarController as? SwipeableTabBarController {
swipeTabBarController.isSwipeEnabled = enabled
}
}
}
class MainTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(SwipeableTabBarController)
}
You can't add a user defined type SwipeableTabBarController tab as a subview here
view.addSubview(SwipeableTabBarController)
you need to add an instance like
let vc = SwipeableTabBarController()
self.addChild(vc)
vc.view.frame = self.view.bounds
view.addSubview(vc.view)
vc.willMove(toParent:self)
if your tabBarController is the root view controller of the app, use this, please.
if let window = UIApplication.shared.keyWindow,
let tabBar = window.rootViewController as? SwipeableTabBarController {
tabBar.isSwipeEnabled = enabled
}

how to segue to storyboard viewcontroller from xib view with swift 3

I'm having the hardest time finding an answer for this.
I have a xib view that is within a scrollview that is within a view controller. In the xib I have a button with an action and I need to segue to a view controller I have in my storyboard. I also would like to be able to use a custom segue.
So far, I have read that I can instantiate the viewcontroller from the storyboard to segue to it. But then I don't know how to present that controller.
thanks for any help...
UPDATE:
this is the code I'm using to perform the segue.
In parent ViewController:
static var referenceVC: UIViewController?
override func viewDidLoad() {
super.viewDidLoad()
print("viewdidload")
LevelSelectViewController.referenceVC = self
setupScrollView()
}
code in xib view file
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "sightWordController")
let parent = LevelSelectViewController.referenceVC!
let segue = InFromRightCustomSegue(identifier: "test", source: parent, destination: vc)
segue.perform()
As noted in the comments, Segues are typically confined to storyboard usage as noted in the documentation. You can implement a custom xib view in a storyboard via #IBDesignable like approaches and have you're view load from the xib into the storyboard file/class. This way, you gain the benefits of both worlds. Otherwise, you may want to approach this in another fashion (such as delegates/target-action events, etc).
You may also climb the responder chain and call a segue related to the VC loaded from the storyboard (the segue doesn't necessarily have to be attached to any particular action) via getting a reference to the VC and calling the segue. You can climb the responder chain in a manner such as the example code below:
protocol ChildViewControllerContainer {
var parentViewController: UIViewController? { get }
}
protocol ViewControllerTraversable {
func viewController<T: UIViewController>() -> T?
}
extension UIView: ViewControllerTraversable {
func viewController<T: UIViewController>() -> T? {
var responder = next
while let currentResponder = responder {
guard responder is T else {
responder = currentResponder.next
continue
}
break
}
return responder as? T
}
}
extension UITableViewCell: ChildViewControllerContainer {
weak var parentViewController: UIViewController? {
return viewController() as UIViewController?
}
}

Update UITabBarController bar item from NSObject class

I have NSObject class listening for a specific event from my server.
When this specific event happens, I would like to update the badge value of an existing tabBar item from my UITabBarController called TabBarController.
How can I access it from the NSObject class?
Below is the NSOBject class listening for the event.
The function connectedToSocketIo() is launched when the application is launched.
The print("Event is working") is displayed in the terminal so everything is working.
The only thing I need now is to be able to update the badge of a specific bar item.
import Foundation
import UIKit
import SwiftyJSON
class SocketIOManager: NSObject{
func connectedToSocketIo(){
socket.on("post-channel:App\\Events\\contact\\newContactRequest"){ (data, ack) -> Void in
let json = JSON(data)
if json[0]["id"].string! == self.defaults.stringForKey("user_id")! {
print("event is working")
// I want to change the tab bar item badge here
} else {
print("no event")
}
}
}
}
You should try to get a reference to the UITabBarController in your SocketIOManager class. Once you have a reference the tab bar controller you can change the badge value of the desired UITabBarItem.
import Foundation
import UIKit
import SwiftyJSON
class SocketIOManager: NSObject {
/*
var tabBarController: UITabBarController!
*/
// When the tabBarController gets set the connectedToSocketIO function gets automatically called.
var tabBarController: UITabBarController! {
didSet {
connectedToSocketIO()
}
}
init() {
super.init()
}
// Either call this function
init(tabBarController: UITabBarController) {
super.init()
self.tabBarController = tabBarController
connectedToSocketIO()
}
// Or create a setter
func setTabBarController(tabBarController: UITabBarController) {
self.tabBarController = tabBarController
}
func connectedToSocketIo() {
socket.on("post-channel:App\\Events\\contact\\newContactRequest"){ (data, ack) -> Void in
let json = JSON(data)
if json[0]["id"].string! == self.defaults.stringForKey("user_id")! {
print("event is working")
// Set the desired tab bar item to a given value
tabBarController!.tabBar.items![0].badgeValue = "1"
} else {
print("no event")
}
}
}
}
EDIT
class CustomTabBarController: UITabBarController {
var socketIOManager: SocketIOManager!
viewDidLoad() {
super.viewDidLoad()
socketIOManager = SocketIOManager(tabBarController: self)
}
}
Hope this helps!
#Jessy Naus
I removed:
the socket connection from the app delegate,
the override init function inside the socketIOManager so the init(UITabBarController)
and added the socket.connect() (from socket.io library) function inside the init function linked to the tab bar controller as follow:
init(tabBarController: UITabBarController) {
super.init()
self.tabBarController = tabBarController
socket.connect()
self.listeningToSocketEvent()
}
I have replaced "self.connectedToSocketIo()" by "listeningToSocketEvent()" has the meaning of this function is more clear.
All together following your instructions mentioned above = Works perfectly. So I put your answer as the good one.
Really not easy concept. Will still need some time to assimilate it and apply it to other components of the UI.
Thanks a lot for your help on this!
actually, I found another way which avoid touching my socket.io instance.
Source:
Swift 2: How to Load UITabBarController after Showing LoginViewController
I just make the link with my tab bar controller as follow:
In my SocketIOManager
//"MainTabBarController" being the UITabBarController identifier I have set in the storyboard.
//TabBarController being my custom UITabBarController class.
// receivedNotification() being a method defined in my custom TabBarController class
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let tabBarController: TabBarController = mainStoryboard.instantiateViewControllerWithIdentifier("MainTabBarController") as! TabBarController
tabBarController.receivedNotification(1)
In my TabBarController class:
func receivedNotification(barItem: Int){
if let actualValue = self.tabBar.items![barItem].badgeValue {
let currentValue = Int(actualValue)
self.tabBar.items![barItem].badgeValue = String(currentValue! + 1)
} else {
self.tabBar.items![barItem].badgeValue = "1"
}
// Reload tab bar item
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window?.rootViewController = self
}