krzyzanowskim / Natalie

Natalie - Storyboard Code Generator (for Swift)
http://blog.krzyzanowskim.com/2015/04/15/natalie-storyboard-code-generator/
MIT License
1.17k stars 74 forks source link

OS X support is broken #75

Closed tonyarnold closed 8 years ago

tonyarnold commented 8 years ago

Running what's in master against my OS X Storyboard, I get references to UIStoryboard and UIViewController. Changing these to NSStoryboard and NSViewController gives me an error: ambiguous use of identifier (on line 13).

//
// Autogenerated by Natalie - Storyboard Generator Script.
// http://blog.krzyzanowskim.com
//

import Cocoa

//MARK: - Storyboards

extension UIStoryboard {
    func instantiateViewController<T: UIViewController where T: IdentifiableProtocol>(type: T.Type) -> T? {
        let instance = type.init()
        if let identifier = instance.identifier {
            return self.instantiateViewControllerWithIdentifier(identifier) as? T
        }
        return nil
    }
}

protocol Storyboard {
    static var storyboard: NSStoryboard { get }
    static var identifier: String { get }
}

struct Storyboards {

    struct Main: Storyboard {

        static let identifier = "Main"

        static var storyboard: NSStoryboard {
            return NSStoryboard(name: self.identifier, bundle: nil)
        }

        static func instantiateWindowControllerWithIdentifier(identifier: String) -> NSWindowController {
            return self.storyboard.instantiateControllerWithIdentifier(identifier) as! NSWindowController
        }

        static func instantiateViewController<T: UIViewController where T: IdentifiableProtocol>(type: T.Type) -> T? {
            return self.storyboard.instantiateViewController(type)
        }

        static func instantiateViewControllerWithIdentifier(identifier: String) -> NSViewController {
            return self.storyboard.instantiateControllerWithIdentifier(identifier) as! NSViewController
        }

        static func instantiateViewController<T: UIViewController where T: IdentifiableProtocol>(type: T.Type) -> T? {
            return self.storyboard.instantiateViewController(type)
        }

        static func instantiateDocumentWindowController() -> NSWindowController {
            return self.storyboard.instantiateControllerWithIdentifier("Document Window Controller") as! NSWindowController
        }
    }
}

//MARK: - ReusableKind
enum ReusableKind: String, CustomStringConvertible {
    case TableViewCell = "tableViewCell"
    case CollectionViewCell = "collectionViewCell"

    var description: String { return self.rawValue }
}

//MARK: - SegueKind
enum SegueKind: String, CustomStringConvertible {    
    case Relationship = "relationship" 
    case Show = "show"                 
    case Presentation = "presentation" 
    case Embed = "embed"               
    case Unwind = "unwind"             
    case Push = "push"                 
    case Modal = "modal"               
    case Popover = "popover"           
    case Replace = "replace"           
    case Custom = "custom"             

    var description: String { return self.rawValue } 
}

//MARK: - SegueProtocol
public protocol IdentifiableProtocol: Equatable {
    var identifier: String? { get }
}

public protocol SegueProtocol: IdentifiableProtocol {
}

public func ==<T: SegueProtocol, U: SegueProtocol>(lhs: T, rhs: U) -> Bool {
    return lhs.identifier == rhs.identifier
}

public func ~=<T: SegueProtocol, U: SegueProtocol>(lhs: T, rhs: U) -> Bool {
    return lhs.identifier == rhs.identifier
}

public func ==<T: SegueProtocol>(lhs: T, rhs: String) -> Bool {
    return lhs.identifier == rhs
}

public func ~=<T: SegueProtocol>(lhs: T, rhs: String) -> Bool {
    return lhs.identifier == rhs
}

public func ==<T: SegueProtocol>(lhs: String, rhs: T) -> Bool {
    return lhs == rhs.identifier
}

public func ~=<T: SegueProtocol>(lhs: String, rhs: T) -> Bool {
    return lhs == rhs.identifier
}

//MARK: - ReusableViewProtocol
public protocol ReusableViewProtocol: IdentifiableProtocol {
    var viewType: NSView.Type? { get }
}

public func ==<T: ReusableViewProtocol, U: ReusableViewProtocol>(lhs: T, rhs: U) -> Bool {
    return lhs.identifier == rhs.identifier
}

//MARK: - Protocol Implementation
extension NSStoryboardSegue: SegueProtocol {
}

//MARK: - NSViewController extension
extension NSViewController {
    func performSegue<T: SegueProtocol>(segue: T, sender: AnyObject?) {
        if let identifier = segue.identifier {
            performSegueWithIdentifier(identifier, sender: sender)
        }
    }

    func performSegue<T: SegueProtocol>(segue: T) {
        performSegue(segue, sender: nil)
    }
}

//MARK: - NSWindowController extension
extension NSWindowController {
    func performSegue<T: SegueProtocol>(segue: T, sender: AnyObject?) {
        if let identifier = segue.identifier {
            performSegueWithIdentifier(identifier, sender: sender)
        }
    }

    func performSegue<T: SegueProtocol>(segue: T) {
        performSegue(segue, sender: nil)
    }
}

//MARK: - ViewController
krzyzanowskim commented 8 years ago

can you create sample project with the setup ?

tonyarnold commented 8 years ago

Here's a sample project demonstrating the issue: https://dl.dropboxusercontent.com/u/153352/Natalie%20OS%20X%20Test.zip

tonyarnold commented 8 years ago

You can see pretty clearly in master at natalie.swift#L1154 that UIKit classes are being output regardless of the platform.

I'm not sure how to fix the ambiguous reference to identifier.

tonyarnold commented 8 years ago

I believe the ambiguity might come from NSViewController conforming to NSUserInterfaceItemIdentification, which already has an identifier property.

tonyarnold commented 8 years ago

Confirmed — renaming identifier to storyboardIdentifier in my Storyboards.swift file lets if compile.

There was also an empty protocol that was unfulfilled:

//MARK: - Protocol Implementation
extension NSStoryboardSegue: SegueProtocol {
}

And NSViewController has no instantiateViewControllerWithIdentifier() — it is instantiateControllerWithIdentifier().

krzyzanowskim commented 8 years ago

want to prepare PR?

krzyzanowskim commented 8 years ago

I think this issue is addressed now.

tonyarnold commented 8 years ago

Sorry I didn't get to the PR :(

Two last things:

  1. NSStoryboard has -instantiateControllerWithIdentifier:, not instantiateViewControllerWithIdentifier:
  2. I'm seeing 2 idential Storyboards.Storyboard.instantiateViewController() methods output
krzyzanowskim commented 8 years ago
  1. is looks ok for OSX, there is NSViewController or NSWindowController
tonyarnold commented 8 years ago

I've tackled the first problem in #77. I think my second issue may be caused by view controllers in my storyboard that have no custom class set yet.

krzyzanowskim commented 8 years ago

thanks! I just pushed one more change to this, please verify.