Custom init while creating view with storyboard or programmatically - xcode

I am trying to create a subclass of UIViewController and then through the storyboard or programmatically pass data to it. What I have tried so far is to have a subViewController swift file with a class subViewController that is a UIViewController
import UIKit
class subViewController: UIViewController {
var s1 = String()
init(myString: String) {
self.s1 = myString
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
#IBOutlet var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
print(self.s1)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
then in Identity Inspector I connect this to the view controller
and in AppDelegate.swift
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let SubVC = subViewController(myString: "Komic")
self.window?.rootViewController = SubVC
self.window?.makeKeyAndVisible()
return true
}
This loads a black screen but it logs out myString. As far as I understand it doesn't create the view but it just creates the instance of the class and that's why it's giving me the black screen. I also know that this part
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
runs when the storyboard gives you the view. But I can't pass data in there that's why I am trying to do this programmaticaly. Is it possible somehow to do that? I know I could instantiateWithIdentifier with the storyboard but I can't find a way to pass my data through that....any help?

An (ugly) way to solve this issue:
You can set your var s1 from an external buffer in your code (AppDelegate variable in this example)
required init?(coder aDecoder: NSCoder) {
self.s1 = UIApplication.shared().delegate.bufferForS1
super.init(coder: aDecoder)
}
And when you initiate your UIViewController through Storyboard:
UIApplication.shared().delegate.bufferForS1 = myS1Value
self.navigationController!.pushViewControllerFading(self.storyboard!.instantiateViewController(withIdentifier: "myViewControllerID") as UIViewController)

You are not loading the view controller from the storyboard when you call your custom initialiser, if you create a customer initialiser it is your responsibility to create the view hierarchy programatically - typically in loadView() although lots of people do it in viewDidLoad().
In Order to the load the view hierarchy you defined in the storyboard you can do this:
let storyBoard = UIStoryboard(name: "storyboardName", bundle: NSBundle.mainBundle())
let viewController = storyBoard.instantiateViewControllerWithIdentifier("storyboardId")
You define the storyboard Id of a view controller in the identity inspector

Related

UILabel and UIButton coming as nil in all uiviewcontroller subclasses swift

I'm trying to create a header which is common for all UIViewControllers. So i have created a ParentViewController class sub classed from UIViewController which is having one UIButton and UILabel in header view.
And I have created a subclass ChildViewController from ParentViewController class. But in ChildViewController UIButton and UILabel are coming as nil.
I have created UIButton and UILabel in storyboard and connected outlet too.
Also I have changed ChildViewController super class to ParentViewController in storyboard. I'm struck.
I'm using below code.
Parent view controller
import UIKit
class ParentViewController: UIViewController {
#IBOutlet weak var viewTitle: UILabel!
#IBOutlet weak var menuButton : UIButton!
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Child view controller
import UIKit
class ChildViewController: ParentViewController {
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.viewTitle.text = "String"
}
}
viewTitle coming as nil.
it's giving ("init(coder:) has not been implemented") error. can anyone help me?

custom datasource method is not calling in swift 2.0

here is my BorderView and The task I'm trying to do is to hookup the custom object (Border) to the main storyboard.
import UIKit
protocol BorderViewDataSource: class{
func colorForBorderView(sender:BorderView) -> String? }
class BorderView: UIView {
#IBOutlet weak var topLeftImage: UIImageView!
#IBOutlet weak var topRightImage: UIImageView!
#IBOutlet weak var bottomLeftImage: UIImageView!
#IBOutlet weak var bottomRightImage: UIImageView!
var view: UIView!
weak var dataSource:BorderViewDataSource?
override init(frame: CGRect) {
super.init(frame: frame)
xtraSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xtraSetup()
}
func xtraSetup() {
view = loadViewFromNib()
// use bounds not frame or it'll be offset
view.frame = bounds
// Make the view stretch with containing view
view.autoresizingMask = [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleHeight]
// Adding custom subview on top of our view (over any custom drawing > see note below)
addSubview(view)
let borderColor = dataSource?.colorForBorderView(self) ?? "red"
applyColor(borderColor)
}
// this is an actual load from nib module
func loadViewFromNib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "BorderView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
func applyColor(borderColor:String){
var imageName = "border-topleft-\(borderColor)"
topLeftImage.image = UIImage(named: imageName)
imageName = "border-topright-\(borderColor)"
print("Border color is \(borderColor), and Last image name is \(imageName)")
}
}
So when i open the app it will show the image of different color depending on what the value of the color is set in the ViewContorller.swift and here is my viewcontroller. swift code
class ViewController: UIViewController, BorderViewDataSource {
var borderType = 2
#IBOutlet weak var borderView: BorderView!{
didSet{
borderView.dataSource = self
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func colorForBorderView(sender: BorderView) -> String? {
var borderColor = "blue"
switch borderType {
case 1: borderColor = "blue"
case 2: borderColor = "purple"
case 3: borderColor = "red"
default: break
}
print("Border Type is \(borderType), and border color is \(borderColor)")
return borderColor
}
}
but colorForBorderView method is not calling when i running the app
It seems when the view is initialized, the dataSource property of that view is nil. And you only call that method during initialization of your view. You can apply the color after viewDidLoad() in your view controller
From the documentation:
When you assign a default value to a stored property, or set its
initial value within an initializer, the value of that property is set
directly, without calling any property observers.
That's the reason why the datasource is not set. Put the line borderView.dataSource = self into viewDidLoad()

Replace NSViewController under Swift2 Storyboard MAC OSX

I am new to Mac OSX and with Apple promoting the fact that the bodies of code are becoming similar decided to tell the folk I am writing code for we should be able to do a Mac OSX version. iPhone and iPad versions are all good and about to release second version so no issues there.
So I am subclassing NSWindowController to get access to the Toolbar and worked out how to remove and add items on the toolbar, but for the life of me I can not get one NSViewController (firstViewController) to dismiss and bring up the second NSViewController (secondViewController) in the same NSWindowController.
So the 2 issues are that
1. I want to be able to performSegueWithIdentifier from the first NSViewController in code and
2. bring up the second NSViewController by replacing the first NSViewController in the same NSWindowController.
If I add a button to the firstViewController and put a segue to the secondViewController then when I select the button the secondViewController comes up just fine but in a seperate window not the same NSWindowController that I want it to and the firstViewController does not get replaced but stays in the NSWindowController.
So I know the segue idea will work but its not working in code and when I do insert the segue from a button it works but into a seperate NSViewController that is not part of the NSWindowController.
I am trying to find some programming guide from Apple on the issue but no luck so far.
Here is an overview from my Storyboard:
Here is my NSWindowController subclassed and the func loginToMe2Team is trigger from the NSToolBar and its working just find as the print statements show up on the console.
import Cocoa
class me2teamWindowsController: NSWindowController {
#IBOutlet var mySignUp : NSToolbarItem!
#IBOutlet var myToolbar : NSToolbar!
let controller = ViewController()
override func windowDidLoad() {
super.windowDidLoad()
print("window loaded")
}
override func windowWillLoad() {
print("window will load")
}
#IBAction func logInToMe2Team(sender: AnyObject){
controller.LogIn() //THIS IS THE FUNC I AM TESTING WITH
}
#IBAction func signUpToMe2Team(sender: AnyObject){
controller.signUp()
}
Here is my NSViewController subclassed with the func LogIn. Its getting selected just fine but the performSegueWithIdentifier is not. And I did cut and past the Identifier to make absolutely sure it was the same.
import Cocoa
import WebKit
class ViewController: NSViewController {
#IBOutlet weak var theWebPage: WebView!
#IBOutlet weak var progressIndicator: NSProgressIndicator!
override func viewDidLoad() {
super.viewDidLoad()
let urlString = "https://thewebpage.com.au"
self.theWebPage.mainFrame.loadRequest(NSURLRequest(URL: NSURL(string: urlString)!))
}
override func viewDidAppear() {
}
func LogIn() {
print("I logged in")
self.performSegueWithIdentifier("goToTeamPage", sender: self)
//THIS IS THE BIT THATS NOT WORKING
}
func signUp() {
print("I have to sign up now")
}
override var representedObject: AnyObject? {
didSet {
}
}
func webView(sender: WebView!, didStartProvisionalLoadForFrame frame: WebFrame!)
{
self.progressIndicator.startAnimation(self)
}
func webView(sender: WebView!, didFinishLoadForFrame frame: WebFrame!)
{
self.progressIndicator.stopAnimation(self)
}
}
You need to use a custom segue class (or possibly NSTabViewController if it’s enough for your needs). Set the segue’s type to Custom, with your class name specified:
…and implement it. With no animation, it’s simple:
class ReplaceSegue: NSStoryboardSegue {
override func perform() {
if let src = self.sourceController as? NSViewController,
let dest = self.destinationController as? NSViewController,
let window = src.view.window {
// this updates the content and adjusts window size
window.contentViewController = dest
}
}
}
In my case, I was using a sheet and wanted to transition to a different sheet with a different size, so I needed to do more:
class ReplaceSheetSegue: NSStoryboardSegue {
override func perform() {
if let src = self.sourceController as? NSViewController,
let dest = self.destinationController as? NSViewController,
let window = src.view.window {
// calculate new frame:
var rect = window.frameRectForContentRect(dest.view.frame)
rect.origin.x += (src.view.frame.width - dest.view.frame.width) / 2
rect.origin.y += src.view.frame.height - dest.view.frame.height
// don’t shrink visible content, prevent minsize from intervening:
window.contentViewController = nil
// animate resizing (TODO: crossover blending):
window.setFrame(window.convertRectToScreen(rect), display: true, animate: true)
// set new controller
window.contentViewController = dest
}
}
}

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.

Resources