Cannot replace views in swift for OS X - macos

probably I don't understand how views works in swift. I'm trying to replace view in my LoginViewController but nothing is happening.
#IBAction func loginBtn(sender: AnyObject) {
let authViewController = AuthViewController(nibName: "AuthView", bundle: nil)!
let appDelegate = NSApplication.sharedApplication().delegate as AppDelegate
appDelegate.window.contentView.replaceSubview(self.view, with: authViewController.authView)
}
and my AppDelegate.swift
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
#IBOutlet weak var customView: NSView!
#IBOutlet weak var statusMenu: NSMenu!
func applicationDidFinishLaunching(aNotification: NSNotification) {
let loginViewController = LoginViewController(nibName: "LoginView", bundle: nil)!
window.contentView.addSubview(loginViewController.view)
}
func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
}

I'm not sure but will it help if you tell frame after your replace subview?
let authViewController = AuthViewController(nibName: "AuthView", bundle: nil)!
let appDelegate = NSApplication.sharedApplication().delegate as AppDelegate
appDelegate.window.contentView.replaceSubview(self.view, with: authViewController.authView)
authViewController.view.frame = (appDelegate.window.contentView as! NSView).frame

loginViewController will be deallocated right away as nobody is holding it. Same is true for authViewController
=> VIEWS don't hold their VIEW CONTROLLERS so the views will go away right away
make a member variable to hold on to them

Related

How to call function in NSViewController?

class CustViewController: NSViewController {
#IBOutlet weak var tableView: NSTableView!
#IBOutlet weak var statusLabel: NSTextField!
fileprivate var selectedOptionFromMenu = ""
#objc var contacts:[Person] = []
#objc var backUpContacts:[Person] = []
#IBAction func printCustomers(_ sender: Any?) {
I would like to call the printCustomers function from another class (NSWindowController). How is this coded in the NSWindowController class?
I tried the following:
let printAction = CustViewController.printCustomers(<#T##self: CustViewController##CustViewController#> )
but don't know how to code argument in this and this may be not be the way to do this?
I used an observer to notify when to run the code in the ViewController
The following is the code I used to accomplish this:
In the main WindowController
public let printNotification = Notification.Name("printNotification")
#IBAction func cashToMePrinting(_ sender: Any?) {
switch activeWindow {
case activeView.customerView:
let printCustNC = NotificationCenter.default
printCustNC.post(name: printNotification, object: nil)
default:
print()
}
}
Added the #IBAction to the responder chain using toolbar print item
Then in the ViewController I added:
#objc func reactToNotification(_ sender: Notification) {
// Do what you need, including updating IBOutlets
printCustomers(Any?.self)
}

Using NSView in NSTableView?

I have searched a lot and but I am not able to find solution for my problem. Seems it is very easy for everyone.
I am trying to create a NSTableView which have NSView cells. But those NSViews will be complicated so I decided to use separate NSViewController for these NSViews so that I can handle actions separately.
Here is what I have done-
This is My StoryBoard-
I am trying to use ViewController for each of cells in NSTableView.
This View is very simple currently(only two labels) but there will be few buttons and image views in future.
the view controller have identifier "rowCell".
I have did this-
extension CMCenterTableViewController:NSTableViewDataSource{
func numberOfRowsInTableView(tableView: NSTableView) -> Int {
return self.conversationData.count
}
func tableView(tableView: NSTableView, viewForTableColumn tableColumn: NSTableColumn?, row: Int) -> NSView?
{
var centralStoryBoard = NSStoryboard(name: "Main", bundle: nil)
var rowCellID: AnyObject? = centralStoryBoard?.instantiateControllerWithIdentifier("rowCell")
var castedView = rowCellID as! CMRowCellView
castedView.view.frame = CGRectMake(self.view.frame.minX, self.view.frame.minY, self.view.frame.width, 75)
(castedView as CMRowCellView).SubjectLable.stringValue = (conversationData[row].valueForKey("subject") as? String)!
(castedView as CMRowCellView).FromLable.stringValue = (conversationData[row].valueForKey("fromAddress") as? String)!
return castedView . view
}
}
This is viewController -
import Cocoa
class CMRowCellView: NSViewController {
#IBOutlet weak var FromLable: NSTextField!
#IBOutlet weak var SubjectLable: NSTextField!
var from:String?
var subject:String?
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
}
}
This works Ok but there is slowness in scroll because views are loaded each time and they are not being reused.
My problem is I want to reuse these view with makeViewWithIdentifier, But I can't find a way to do so.
And also Is it correct way to use view controllers in NSTableView?
Thanks for your help.

Could not cast value of type 'UINavigationController' (0x10836e698) to 'UITabBarController' (0x10836e6e8).?

This is the code for UITabBarController in which I am trying to open a splitviewcontroller.
import UIKit
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
///here after this line I am getting error
var mainCont : UITabBarController = ((UIApplication.sharedApplication().delegate) as! AppDelegate).window?.rootViewController as! UITabBarController
var navCont2 : UINavigationController? = mainCont.viewControllers?[1] as? UINavigationController
var controller = UIStoryboard(name: "Storyboard2", bundle: nil).instantiateInitialViewController() as! UISplitViewController
controller.preferredDisplayMode = UISplitViewControllerDisplayMode.AllVisible
navCont2?.presentViewController(controller, animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Your first line:
var mainCont : UITabBarController = ((UIApplication.sharedApplication().delegate)
as! AppDelegate).window?.rootViewController as! UITabBarController
Is getting the window's rootViewController as UITabBarController. And the error message is really kind of clear:
Could not cast value of type 'UINavigationController' (0x10836e698) to 'UITabBarController' (0x10836e6e8).
On app start the window's rootViewController is set to what ever you have defined as your initial view controller on the Storyboard (The big grey arrow). My guess is that your initial view controller is set to a UINavigationController, but in your code you are trying to cast (force) it to be a UITabBarController.

Cannot invoke <method> with and argument list of type '(String)'

Im trying to write an OSX app. A functionality of this app is that it displays the machine IP address.
The address is fetched when the program is opened (AppDelegate.swift):
#NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate {
var ipadd:String = ""
var path:String = ""
var status:String = ""
func applicationDidFinishLaunching(aNotification: NSNotification) {
ipadd = getIFAddress() //<-- ip stored in here as String
println(ipadd) //successfully prints out the ip
ViewController.setIpDisp(ipadd) //error on this line
}
...
}
And in ViewController.swift:
class ViewController: NSViewController {
#IBOutlet weak var ip: NSTextField!
...
func setIpDisp(ipin: String){
ip.stringValue = ipin
}
To be exact, the error is "Cannot invoke 'setIpDisp' with an argument list of type '(String)'
Thanks
The AppDelegate is trying to call a ViewController method that is updating an #IBOutlet in the view controller's view. It needs a valid ViewController instance to do that.
But this is backwards: The app delegate should not be trying to call view controller methods. The view controller can call methods/properties of the app delegate, but the app delegate really shouldn't be calling view controller methods.
If you need to update the IP number field in the view controller, then the view controller should be initiating this (e.g. in viewDidLoad):
class ViewController: NSViewController {
#IBOutlet weak var ip: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
updateIpDisp()
}
func updateIpDisp() {
let appDelegate = NSApplication.sharedApplication().delegate as! AppDelegate
ip.stringValue = appDelegate.getIFAddress()
}
}
Or, if you wanted, the AppDelegate set some ipadd string property in its init method (not applicationDidFinishLaunching), and then the updateIpDisp() method could retrieve the property's value from the app delegate, too. (Given that IP numbers are dynamic and can change, that doesn't seem right to me, but do it however you want.) Anyway, that might look like:
class AppDelegate: NSObject, NSApplicationDelegate {
var ipadd: String!
override init() {
super.init()
ipadd = getIFAddress()
}
}
and
class ViewController: NSViewController {
#IBOutlet weak var ip: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
updateIpDisp()
}
func updateIpDisp() {
let appDelegate = NSApplication.sharedApplication().delegate as! AppDelegate
ip.stringValue = appDelegate.ipadd
}
}
But the view controller should be requesting the IP number from the app delegate and updating its own view. But the app delegate has no business calling methods in the view controller(s).
Your function isn't static, so make sure to initialise an instance of it, like so
#NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate {
let viewController = ViewController()
var ipadd:String = ""
var path:String = ""
var status:String = ""
func applicationDidFinishLaunching(aNotification: NSNotification) {
ipadd = getIFAddress() //<-- ip stored in here as String
println(ipadd) //successfully prints out the ip
viewController.setIpDisp(ipadd) //error on this line
}
...
}

How to pass data from NSWindowController to its NSViewController?

I have a IBOutlet of a NSToolBar button in my NSWindowController class, which is my main window class:
class MainWindowController: NSWindowController {
#IBOutlet weak var myButton: NSButton!
// ...
}
I have a class MainViewController that is that content NSViewController of the main window.
How can I access this button in my content NSViewController? Is there a better way to organize the IBOutlets and the controllers to facilitate this access?
To access NSViewController from NSWindowController:
let viewController:MainViewController = self.window!.contentViewController as! MainViewController
To access NSWindowController from NSViewController:
let windowController:MainWindowController = self.view.window?.windowController as! MainWindowController
How about like this using delegate? This example will change your button's title.
#objc protocol SomeDelegate {
func changeTitle(title: String)
}
class ViewController: NSViewController {
weak var delegate: SomeDelegate?
#IBAction func myAction(sender: AnyObject) {
delegate?.changeTitle("NewTitle")
}
}
class MainWindowController: NSWindowController, SomeDelegate {
#IBOutlet weak var myButton: NSButton!
override func windowDidLoad() {
super.windowDidLoad()
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
let myVc = window!.contentViewController as! ViewController
myVc.delegate = self
}
func changeTitle(title: String) {
myButton.title = title
}
}

Resources