Override multiple overloaded init() methods in Swift - swift

I'm attempting to create a custom NSTextFieldCell subclass in Swift (Xcode Beta 5), with the following code:
class CustomHighlightTextFieldCell : NSTextFieldCell {
required init(coder aCoder: NSCoder!) {
super.init(coder: aCoder)
}
init(imageCell anImage: NSImage!) {
super.init(imageCell: anImage)
}
init(textCell aString: String!) {
super.init(textCell: aString)
}
}
However, I receive compilation errors on the 2nd and 3rd init() declarations:
/Users/Craig/projects/.../CustomHighlightTextFieldCell:8:40: Invalid redeclaration of 'init(imageCell:)'
/Users/Craig/projects/.../CustomHighlightTextFieldCell.swift:17:5: 'init(imageCell:)' previously declared here
/Users/Craig/projects/.../CustomHighlightTextFieldCell:7:39: Invalid redeclaration of 'init(textCell:)'
/Users/Craig/projects/.../CustomHighlightTextFieldCell.swift:21:5: 'init(textCell:)' previously declared here
While there are some strange compiler bugs here (I'm getting the usual "SourceKitService Terminated, Editor functionality temporarily limited." message), it seems like I'm missing something in my method overriding - but I can't tell what.
I was under the assumption the named parameters, or at least the parameter types, would indicate that there are three different init() methods here, but apparently I'm missing a key piece of the puzzle.
Edit: If I add override to the 2nd and 3rd init() methods, I have a separate issue:
required init(coder aCoder: NSCoder!) {
super.init(coder: aCoder)
}
override init(imageCell anImage: NSImage!) {
super.init(imageCell: anImage)
}
override init(textCell aString: String!) {
super.init(textCell: aString)
}
This new issue (simply invoked by adding the two override keywords) seems to almost contradict the original.
/Users/Craig/projects/.../CustomHighlightTextFieldCell.swift:17:14: Initializer does not override a designated initializer from its superclass
/Users/Craig/projects/.../CustomHighlightTextFieldCell.swift:21:14: Initializer does not override a designated initializer from its superclass

It would seem that your declarations (with override) should be sufficient, however, they seem to need the #objc declarations as well. This works:
class CustomHighlightTextFieldCell : NSTextFieldCell {
required init(coder aCoder: NSCoder!) {
super.init(coder: aCoder)
}
#objc(initImageCell:)
override init(imageCell anImage: NSImage!) {
super.init(imageCell: anImage)
}
#objc(initTextCell:)
override init(textCell aString: String!) {
super.init(textCell: aString)
}
}

As you see, you have the corresponding super.init(xxx) in the functions which means you are overriding the functions. So just add the override keyword.
override init(imageCell anImage: NSImage!) {
super.init(imageCell: anImage)
}
override init(textCell aString: String!) {
super.init(textCell: aString)
}

Related

Why is this subclass failing to be archived by NSKeyedArchived?

I have this class that have to be the subclass of OIDAuthState (this class is an NSObject and conforms to NSSecureCoding),
The code to encode the class OIDAuthState was working fine before
self.data = try NSKeyedArchiver.archivedData(withRootObject: authState, requiringSecureCoding: true)
Once I created this subclass that includes adds a simple Boolean to the class isExpiredTokenEnforced, I now get the error when using NSKeyedArchiver,
The error says:
NSDebugDescription=Caught exception during archival: *** -decodeBoolForKey: only defined for abstract class. Define -[NSKeyedArchiver decodeBoolForKey:]!
Here is the subclass I am trying to archive and down below the override method to encode and decode this class, I am simply encoding and decoding this 1 extra property and then passing down the coder to the parent class,
class AuthenticationStateManager: OIDAuthState, AuthenticationState {
var isExpiredTokenEnforced = false
var lastTokenResponseInterface: TokenResponse? {
if isExpiredTokenEnforced {
return EnforcedExpiredTokenResponse(idToken: super.lastTokenResponse?.idToken,
accessToken: super.lastTokenResponse?.accessToken)
} else {
return super.lastTokenResponse
}
}
override static var supportsSecureCoding: Bool { true }
required override init(authorizationResponse: OIDAuthorizationResponse?, tokenResponse: OIDTokenResponse?, registrationResponse: OIDRegistrationResponse?) {
super.init(authorizationResponse: authorizationResponse, tokenResponse: tokenResponse, registrationResponse: registrationResponse)
}
required init?(coder: NSCoder) {
coder.encode(isExpiredTokenEnforced, forKey: "isExpiredTokenEnforced")
super.init(coder: coder)
}
override func encode(with coder: NSCoder) {
self.isExpiredTokenEnforced = coder.decodeBool(forKey: "isExpiredTokenEnforced")
super.encode(with: coder)
}
}
I can't figure out why this is failing I couldn't find relevant information to fix this,
does anyone have a clue what could be wrong here?
Thank you in advance for your time.
You are mixing up your encoder and decoder functions. Your func encode() is trying to call decodeBool. It should be calling encode().
Similarly your init?(coder:) function should be calling decode (or rather decodeBool(forKey:).)

Swift: Generic Protocol Cannot invoke with an argument list of type

Trying to create a generic protocol with associatedtype.
I get an error when I try to access a method from the delegate:
Cannot invoke 'numberOfSections' with an argument list of type '(containerView: UITableView)'
Code:
protocol ViewDelegate: class {
associatedtype ContainerView
associatedtype Model
func numberOfSections(containerView: ContainerView)
func aMethodThatTakesNoArugments()
}
class ViewController: UIViewController {
var newView = AnyView<ViewController>()
override func viewDidLoad() {
super.viewDidLoad()
newView.delegate = self
}
}
extension ViewController: ViewDelegate {
typealias ContainerView = UITableView
typealias Model = Int
func numberOfSections(containerView: ContainerView) {
// do something with containerView
}
func aMethodThatTakesNoArugments() {}
}
class AnyView<Delegate: ViewDelegate>: UIView {
weak var delegate: Delegate?
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func getData() {
delegate?.aMethodThatTakesNoArugments() // This compiles fine
delegate?.numberOfSections(containerView: UITableView()) // Get a compiler error on this line (I am passing an argument):
// Cannot invoke 'numberOfSections' with an argument list of type '(containerView: UITableView)'
}
}
I have a feeling I am missing something. Method that takes no arguments compiles fine; however if I call a method that does take an arugment, I get a compile error.
Your error is due to the compiler not being able to tell what Type ContainerView is supposed to be.
You're only defining it for ViewController, but the Delegate could be literally any class or struct, not just ViewController.
There are a number of ways to fix this, but it's unclear what exactly you're trying to accomplish here, so I'll just give a couple examples:
as #OOPer mentioned, you could constraint your Delegate generic to force conformance to UITableView:
class AnyView<Delegate: ViewDelegate>: UIView where Delegate.ContainerView == UITableView
A similar option would be to simply define the protocol with the desired type:
protocol ViewDelegate: class {
func numberOfSections(containerView: ContainerView)
func aMethodThatTakesNoArugments()
}
If you need more flexibility, another option would be to add another generic Type:
class AnyView<Delegate: ViewDelegate, ContainerViewType>: UIView where Delegate.ContainerView == ContainerViewType

Annotating Swift function declarations that support conformance to a protocol?

Is there a standard mechanism for annotating function declarations in Swift to indicate that they are present because a class conforms to some protocol?
For instance, this declaration might be present because a class conforms to NSCoding. (Marking it with override would result in a syntax error, so it's not the kind of annotation I am looking for.) Ideally I am looking for a code-level annotation (e.g. override instead of /*! ... */).
// ... annotation such as "conform to NSCoding", if possible
func encodeWithCoder(encoder: NSCoder) {
// ...
}
You can use extension. for example:
protocol SomeProtocol {
func doIt() -> Int
}
class ConcreteClass {
....
}
extension ConcreteClass: SomeProtocol {
func doIt() -> Int {
// ...
return 1
}
}
But you cannot define required initializer in extension, for example:
// THIS DOES NOT WORK!!!
class Foo: NSObject {
}
extension Foo: NSCoding {
required convenience init(coder aDecoder: NSCoder) {
self.init()
}
func encodeWithCoder(aCoder: NSCoder) {
// ...
}
}
emits an error:
error: 'required' initializer must be declared directly in class 'Foo' (not in an extension)
required convenience init(coder aDecoder: NSCoder) {
~~~~~~~~ ^
In this case, you should use // MARK: comments:
class Foo: NSObject {
// ...
// MARK: NSCoding
required init(coder aDecoder: NSCoder) {
super.init()
}
func encodeWithCoder(aCoder: NSCoder) {
// ...
}
}

Swift 1.2: 'self' used before super.init call

I have this code:
class SomeViewController : UIViewController {
let deferred : ()->()
required init(coder aDecoder : NSCoder) {
deferred = {
self.doSomething()
}
super.init(coder: aDecoder)
}
func doSomething() {
// Does things....
}
}
In Swift 1.2 this fails to compile with the error:
'self' used before super.init call
In pre-1.2 days, we can address this in a number of ways such as implicitly unwrapped conditionals. That approach won't work any longer.
I've seen other answers reference 2-stage initialization or the lazy decorator, but both sacrifice immutability of the property. Surely this must be solvable in Swift 1.2, but I'm out of ideas.
Here's an interim workaround:
private(set) var deferred : ()->() = { }
required init(coder aDecoder : NSCoder) {
super.init(coder: aDecoder)
self.deferred = {
self.doSomething()
}
}
My thinking is, okay, we did "sacrifice immutability of the property", but from a public perspective the property remains immutable because the setter is private.

Subclassing SCNScene in Swift - override init

I'm getting some compiler errors in Xcode 6 using Swift which I have a hard time wrapping my head around. I'm trying to create a scene by subclassing SCNScene, but keep getting errors on the initialisers. The basic structure of my code is:
class SpaceScene: SCNScene {
override init(named: String) {
super.init(named: named)
}
}
This results in an error on line 2 with the message "Initializer does not override a designated initializer from its superclass", although SCNScene clearly has such an initialiser. I think i'm missing something basic - any insights?
On XCode 6.1, the following should do it:
class SpaceScene : SCNScene {
override init() {
super.init()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}