【问题标题】:Protocol can only be used as a generic constraint because it has Self or associated type requirements协议只能用作通用约束,因为它具有 Self 或关联的类型要求
【发布时间】:2016-08-16 03:42:39
【问题描述】:

我有这个协议:

protocol ViewType {
    associatedtype T: ViewData.View
    var data:T! {get set}
}

ViewData.View 是一个类

我有一个名为TemplateLabel 的类继承UILabel 并符合ViewType

class TemplateLabel:UILabel, ViewType {
    var data: ViewData.View.Label!
}

我从情节提要中得到这个 TemplateLabel 作为 UIView 并尝试将 UIView 转换为 ViewType 以将 data 属性分配给它

let view = SB.instantiateViewControllerWithIdentifier("view_label").view
if var v = view as? ViewType { // Error
    v.data = data // Error
}

但我得到错误:

Protocol 'ViewType' 只能用作通用约束,因为它具有 Self 或关联的类型要求

成员“数据”不能用于协议类型“ViewType”的值;改用通用约束

【问题讨论】:

  • 您应该转换为特定的实现,而不是约束协议。投射到TemplateLabel。并阅读有关 Swift 协议的更多信息 :)
  • @werediver 我有一个具体的原因不直接转换为 TemplateLabel,这是为了让事情变得动态,这只是一个简短的例子
  • 那么你需要一个通用的方法......我可以展示一个例子(几分钟后)。另一种方法是类型擦除,但我认为这太深了。
  • 嗯,我错了。泛型方法无法解决此类问题,因为泛型方法是在编译时为特定类型实例化的,但您的对象类型在编译时是未知的,除非您将其强制转换为特定实现。
  • 观看 Rob Napier 的演讲,深入了解这个问题 - thedotpost.com/2016/01/…

标签: ios swift generics protocols


【解决方案1】:

我有一个答案给你,但那几乎是简单的代码。我认为它真的在定义的上下文中很有用。

import UIKit

// Framework

/**
 * Intended usage:
 *
 *     enum AppStoryboard: BundledStoryboard {
 *
 *         case Login
 *         case Main
 *
 *         var storyboard: UIStoryboard {
 *             return UIStoryboard(name: "\(self)", bundle: nil)
 *         }
 *
 *     }
 */
protocol BundledStoryboard {

    var storyboard: UIStoryboard { get }

}

protocol StoryboardViewController {

    static var bundledStoryboard: BundledStoryboard { get }
    static var storyboardId: String { get }

    static func instantiateFromStoryboard() -> Self

}

extension StoryboardViewController {

    static var storyboardId: String { return "\(self)" }

    static func instantiateFromStoryboard() -> Self {
        return bundledStoryboard.storyboard.instantiateViewControllerWithIdentifier(storyboardId) as! Self
    }

}

// Application specific

enum AppStoryboard: BundledStoryboard {

    //case Login
    case Main

    var storyboard: UIStoryboard {
        return UIStoryboard(name: "\(self)", bundle: nil)
    }

}

extension StoryboardViewController {

    static var bundledStoryboard: BundledStoryboard { return AppStoryboard.Main }

}

// View-Model relation

protocol ViewType {

    associatedtype Model

    func loadModel(m: Model)

}

// ViewController

final class ViewController: UIViewController, StoryboardViewController, ViewType {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    func loadModel(m: UIColor?) {
        view.backgroundColor = m // Strange example, yeah.
    }

}

// Then somewhere...

let vc = ViewController.instantiateFromStoryboard()
vc.loadModel(.redColor())

我认为您在这里并不需要任何动态解决方案。您必须知道您正在实例化什么以及它可以接收什么数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多