ios - self vs "generic typet"扩展时的 T 差异

标签 ios runtime protocols swift-extensions class-extensions

我遇到了一个我不理解的有趣行为。这是产生这种行为的代码:

import UIKit

protocol UIViewNibLoading {
    static var nibName: String { get }
}

extension UIView : UIViewNibLoading {

    static var nibName: String {
        return String(describing: self)
    }

}

extension UIViewNibLoading where Self : UIView {

    static func loadFromNib<T: UIViewNibLoading>() -> T {
        print(T.nibName)
        print(nibName)
        return UINib(nibName: nibName, bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! T
        // CRASH: return UINib(nibName: T.nibName, bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! T
    }

}

这是执行这段代码时控制台的输出:

UIView
MyCustomViewSubclass

当我在自定义类上调用 loadFromNib 方法时。它会产生两种不同的行为,具体取决于我如何获取 nibName

  1. T.nibName:返回字符串 UIView
  2. nibName:返回字符串 MyCustomViewSubclass

你知道这里发生了什么吗?为什么 selfT 在运行时不是同一个对象?这是我发现的另一件有趣的事情。当您将断点放入 nibName getter 时,您可以在调试器中看到以下内容:

T.nibName: T.nibName Nib 名称: nibName

这被称为:

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    if section == WidgetAddTableViewController.SectionIndexRecent {
        return WidgetAddHeaderView.loadFromNib()
    } else if section == WidgetAddTableViewController.SectionIndexFreeAndPremium {
        return WidgetAddFilterHeaderView.loadFromNib()
    }
    return nil
}

感谢任何解释。

最佳答案

self 在运行时解析。 T 在编译时解析。所以在编译时,您的代码表现如下:

let returnValue: UIView? = WidgetAddHeaderView.loadFromNib()
return returnValue

loadFromNib 的返回类型是通用的。鉴于此代码,唯一有效的返回类型是 UIView。同样,这是在编译时决定的。

self 另一方面,只是一个变量。这是一个非常特殊的变量,但它实际上只是一个变量。它具有运行时值。所以 type(of: self) 是在运行时评估的。动态调度在运行时处理。

错误在于您并不是真的要返回“一些符合 UIViewNibLoading 的未知 T”(这就是您所说的通过使返回类型通用而返回的内容)。您要返回的是 Self,静态函数所属的类(在编译时确定)。所以你这么说:

extension UIViewNibLoading where Self : UIView {

    static func loadFromNib() -> Self {
        print(nibName)
        return UINib(nibName: nibName, bundle: nil)
            .instantiate(withOwner: nil, options: nil)[0] as! Self
    }   
}

或者您可以少 promise (因为您的来电者实际上并不关心)并执行此操作:

extension UIViewNibLoading where Self : UIView {

    static func loadFromNib() -> UIView {
        print(nibName)
        return UINib(nibName: nibName, bundle: nil)
            .instantiate(withOwner: nil, options: nil)[0]
    }
}

但是没有理由让这个方法通用,正如你所看到的,它实际上伤害了你。

关于ios - self vs "generic typet"扩展时的 T 差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50514379/

相关文章:

ios - AFHTTPRequestOperationManager 获取请求失败,Error Domain=AFNetworkingErrorDomain Code=-1016

ios - CollectionView 拉动刷新崩溃

Lua:使用表作为参数

algorithm - 递归:T(n)=T(n/2)+ log N

swift - Swift 中所有 IntegerLiteralConvertible 的通用 init 函数

javascript - UIWebView 不正确的内容高度

ios - 如何通过名字对 ABAddressBook 联系人进行排序

actionscript-3 - 除了 Flash 之外的其他运行时中的 ActionScript 3?

ios - swift 中 java 接口(interface)或 objective c 协议(protocol)的等价物是什么?

ios - 协议(protocol)的 Swift 实例