providing a designated initializer for a custom NSView in Swift - xcode

I have a custom NSView Class that looks like:
class MyClass: NSView
{
var myClassVar: NSColor
}
Naturally, Xcode is complaining that my class has no initializers, so I need to override the designated initializer so I can initialize myClassVar.
How can I do this?

Try this;
class MyClass: NSView
{
var myClassVar: NSColor! // the optional mark ! to be noticed.
override init(frame frameRect: NSRect) {
super.init(frame:frameRect);
}
required init(coder: NSCoder) {
super.init(coder: coder)
}
//or customized constructor/ init
init(frame frameRect: NSRect, otherInfo:Int) {
super.init(frame:frameRect);
// other code
}
}

If you give your color a default value, the initializers from NSView should still work.
Here are several ways to do this:
var myClassVar: NSColor?
var myClassVar: NSColor! // make sure to set this before you actually access it
var myClassVar: NSColor = NSColor.clearColor()
The second example (implicitly unwrapped optional) is what Apple does with IBOutlets. Otherwise you would need to have an initializer that sets each of your variables to a non-null value in your init methods.
For more information about this, see Swift Initialization and the Pain of Optionals, which discusses these solutions:
Instantiating it before the call to super.init.
Optional variable (NSColor?), instantiating it after super.init
Implicitly unwrapped optional variable (NSColor!)
Using a lazy property
Using a lazy property with a closure

Related

How to initialize NSTableRowView subclass?

The compiler crashses on line 3 and I cant find information on NSTableRowView initializers anywhere
class ItemRowView: NSTableRowView {
convenience override init(frame: NSRect) {
self.init(frame: frame) // EXC BAD ACCESS
self.draggingDestinationFeedbackStyle = NSTableViewDraggingDestinationFeedbackStyle.None
}
First, init( frame: NSRect )is the designated initializer, so the keyword convenience is wrong in this place.
Then you probably meant to call the super initializer than your own method recursively.
At last you'll need to implement another required initializer init?(coder: NSCoder)
The following code should get you going:
class ItemRowView: NSTableRowView {
override init(frame: NSRect) {
super.init(frame: frame) // super - not self
self.draggingDestinationFeedbackStyle = NSTableViewDraggingDestinationFeedbackStyle.None
}
required init?(coder: NSCoder) {
// Write something useful here, or leave the default implementation
fatalError("init(coder:) has not been implemented")
}
}

Access an IBOutlet from another class in Swift

I'm new to Swift and Mac App.
So I'm writing an Mac App today and I still confuse how to access an IBOutlet from another class after searching a lot.
I'm using StoryBoard and there are two NSTextField path mirror in my ViewController.
I have created a custom class Path.swift for the first NSTextField path to know when the text in path has changed.
class Path: NSTextField, NSTextFieldDelegate
{
override func drawRect(dirtyRect: NSRect)
{
super.drawRect(dirtyRect)
// Drawing code here.
self.delegate = self
}
var current = ""
override func controlTextDidChange(obj: NSNotification)
{
current = self.stringValue
println("Current is \(current)")
}
}
And there are two outlets defined in ViewController.swift
class ViewController: NSViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
#IBOutlet weak var path: NSTextField!
#IBOutlet weak var mirror: NSTextField!
}
And when user type something in the first NSTextField path, I want the second NSTextField mirror shows the same string as path.
I tried to use ViewController().mirror.stringValue = current, but I got fatal error: unexpectedly found nil while unwrapping an Optional value
After googling a lot, I knew that I have created a new instance of ViewController instead of accessing the current existing instance of ViewController.
So my question is how I can access the IBOutlet in ViewController.swift from Path.swift class (how to access the current existing instance of ViewController).
Any help will be greatly appreciated.
Thanks in advance.

Subclass NSView instead of NSTableCellView

This question is an extension to this question.
I am working on Cocoa App, where I am populating a table using Cocoa Bindings.
I am subclassing NSView instead of NSTableCellView
As per NSTableCellView Class Referenence
If you use your own custom view cells that are not based on
NSTableCellView you should implement this property(objectValue) in order to be able
to receive changes to cell values.
Also
swift
var objectValue: AnyObject?
The objectValue is automatically set by the table when using bindings or is th...
This is my class implementation, which I will be using as cell in TableView
class TestView : NSView {
var objectValue: AnyObject?
init(nameA: String, nameB: String) {
super.init(frame: NSMakeRect(3, 3, 300, 40))
objectValue = nameA
let firstName = MyTextField(location: NSMakePoint(10, 10), stringVal: nameA)
self.addSubview(firstName)
let secondName = MyTextField(location: NSMakePoint(250, 10), stringVal: nameB)
self.addSubview(secondName)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
Although having declared the objectValue in TestClass, I am still not able to bind the object value from IB
Custom views and objects don't get custom property bindings in IB. YOU HAVE TO SET UP BINDINGS IN CODE.
You also need to ensure your class does all the fun stuff required to enable bindings.

Failable och non-failable initializers prevents me to extend NSView and implement NSCoding

I'm having problems implementing a subclass to NSView that implements NSCoding.
It seems like the declarations of init(coder: NSCoder) are conflicting in NSView and NSCoding.
NSView nowadays says it's failable, but NSCoding still says it's non-failable.
When I try to override init(coder: NSCoder) and do my custom initialisation, Xcode 6.1 gives me an error message:
A non-failable initializer cannot chain to failable initializer
'init(coder:)' written with 'init?'
How am I supposed to do my custom init of my class?
Here's a silly example where I extend a view and I want to persist an additional click counter for my view.
import Cocoa
import Foundation
class MyView: NSView, NSCoding {
var clickCounter:Int = 0
required init(coder: NSCoder) {
super.init(coder: coder)
coder.encodeObject(self.clickCounter,
forKey: "clickCounter")
}
override func encodeWithCoder(coder: NSCoder) {
super.encodeWithCoder(coder)
coder.encodeObject(self.clickCounter, forKey: "clickCounter")
}
override func mouseDown(theEvent: NSEvent) {
clickCounter++
}
}
You don't have to explicitly conform to NSCoding, because NSResponder (superclass of NSView) already conforms to it.
required init?(coder: NSCoder) {
super.init(coder: coder)
self.clickCounter = coder.decodeObjectForKey("clickCounter") as Int
}

Does NSView have a backgroundColor? If it does, I can't find it

I'm seeing all over the place online where people are referring to NSView's backgroundColor. I need to set a custom backgroundColor to my NSView, but I'm not seeing that property. I can't see it in code, or in IB. I am unable to set the background color of my simple NSView.
What could I be missing?
They must be thinking of UIView, which does have a backgroundColor property. NSView does not have a backgroundColor property.
You will have to achieve your effect some other way, e.g., through subclassing NSView.
Strangely enough NSView does not provide this (sigh). I use one consistent class I wrote myself throughout all my macOs projects. Just change the CustomView class in the Identity Inspector tab in IB to ColorView. You will then be able to set the background color in the Attribute Inspector, just like you would for a UIView. Here's the code, hope this helps!
import Cocoa
class ColorView: NSView
{
#IBInspectable var backgroundColor:NSColor?
required init?(coder decoder: NSCoder)
{
super.init(coder: decoder)
wantsLayer = true
}
override init(frame frameRect: NSRect)
{
super.init(frame: frameRect)
wantsLayer = true
}
override func layout()
{
layer?.backgroundColor = backgroundColor?.cgColor
}
}
You can reach it via the view's layer, e.g. (in Swift):
view.layer?.backgroundColor = NSColor.blue.cgColor
Strangely it can be set in the xib. In the identity inspector for the view, add the User Defined Runtime Attribute backgroundColor, with the Type color.

Resources