self vs [=10T 创建扩展时的区别
self vs "generic typet" T difference when ceating extension
我 运行 陷入一种我不理解的有趣行为。这是产生这种行为的代码:
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
当我在自定义 class 上调用 loadFromNib
方法时。它会产生两种不同的行为,具体取决于我如何获得 nibName
.
- T.nibName:这个returns字符串
UIView
- nibName: 这个 returns 字符串
MyCustomViewSubclass
你知道这里发生了什么吗?为什么self
和T
在运行时间内不是同一个对象?这是我发现的另一件有趣的事情。这是将断点放入 nibName
getter:
时在调试器中可以看到的内容
T.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
在其 return 类型上是通用的。鉴于此代码,唯一有效的 return 类型是 UIView
。同样,这是在编译时决定的。
self
另一方面,只是一个变量。这是一个非常特殊的变量,但它实际上只是一个变量。它有一个 运行 时间值。所以 type(of: self)
在 运行 时计算。动态调度在 运行 时间处理。
错误在于你并不是真的要 return "some unknown T that conforms to UIViewNibLoading"(这就是你说 return 通过使 return 类型通用)。你对return的意思是Self
,静态函数是其成员的class(在编译时确定)。所以你这么说:
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
}
}
或者你可以少承诺(因为你的来电者实际上并不关心)并这样做:
extension UIViewNibLoading where Self : UIView {
static func loadFromNib() -> UIView {
print(nibName)
return UINib(nibName: nibName, bundle: nil)
.instantiate(withOwner: nil, options: nil)[0]
}
}
但是没有理由让这个方法通用,正如你所看到的,它实际上伤害了你。
我 运行 陷入一种我不理解的有趣行为。这是产生这种行为的代码:
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
当我在自定义 class 上调用 loadFromNib
方法时。它会产生两种不同的行为,具体取决于我如何获得 nibName
.
- T.nibName:这个returns字符串
UIView
- nibName: 这个 returns 字符串
MyCustomViewSubclass
你知道这里发生了什么吗?为什么self
和T
在运行时间内不是同一个对象?这是我发现的另一件有趣的事情。这是将断点放入 nibName
getter:
T.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
在其 return 类型上是通用的。鉴于此代码,唯一有效的 return 类型是 UIView
。同样,这是在编译时决定的。
self
另一方面,只是一个变量。这是一个非常特殊的变量,但它实际上只是一个变量。它有一个 运行 时间值。所以 type(of: self)
在 运行 时计算。动态调度在 运行 时间处理。
错误在于你并不是真的要 return "some unknown T that conforms to UIViewNibLoading"(这就是你说 return 通过使 return 类型通用)。你对return的意思是Self
,静态函数是其成员的class(在编译时确定)。所以你这么说:
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
}
}
或者你可以少承诺(因为你的来电者实际上并不关心)并这样做:
extension UIViewNibLoading where Self : UIView {
static func loadFromNib() -> UIView {
print(nibName)
return UINib(nibName: nibName, bundle: nil)
.instantiate(withOwner: nil, options: nil)[0]
}
}
但是没有理由让这个方法通用,正如你所看到的,它实际上伤害了你。