我来自Java背景,当你宣布内部类时,它既是静态的,也不能访问外部类的实例,或者它是“#”。不是静态的,可以访问正在操作的外部类的实例。见http://en.wikipedia.org/wiki/Inner_class#Types_of_nested_classes_in_Java
Swift有这个概念吗?从我的测试来看,我似乎无法访问Outer
的{{1}}对象,但我肯定会做错事。
self
答案 0 :(得分:34)
AFAIK,您无法开箱即用访问外部类。
但你可以做的是:
class Outer {
let value = ""
var inner = Inner()
class Inner {
weak var parent: Outer! = nil
func foo() {
let bar = parent.value
}
}
init() {
inner.parent = self
}
}
或者:
class Outer {
class Inner {
unowned let parent: Outer
init(parent: Outer) {
self.parent = parent
}
}
let value = ""
var inner: Inner! = nil
init() {
inner = Inner(parent: self)
}
}
答案 1 :(得分:3)
嵌套类型无法对包含它们的类型进行任何特殊访问。但是,我不认为这就是他们所做的一切。你似乎对类与实例有点模糊。
value
是外类的属性。这意味着Outer的每个实例都有自己的value
。 Inner是一个独立的类,存在于Outer的命名空间中。所以当你写let bar = value
时,没有value
这样的东西可以访问,因为它只存在于Outer的实例中,而我们手边没有任何实例。如果是类属性,则可以let bar = Outer.value
。
答案 2 :(得分:2)
任何语言的内部类都是一个非常无用的结构。他们没有做任何分离关注的事情。它们只提供了包装类内部的可视化分组,但代码仍然与整个地方的交叉依赖性高度纠缠。
抽象的正确实践是隔离尽可能少的问题(理想情况下,一个)。隔离意味着没有可能的交叉依赖性,这在推理代码时会产生巨大的影响。
问问自己:你真正需要这个外部类的引用是什么? 唯一可能的答案是仅访问其API的某些特定部分。 事实证明,这就是使内部类专门化为特定外部类的冗余。
考虑以下示例:
class CustomSectionContentController : UIViewController {
@IBOutlet weak var webView: UIWebView!
lazy var webViewDelegate: WebViewDelegate = WebViewDelegate()
override func viewDidLoad() {
super.viewDidLoad()
webView.delegate = webViewDelegate
}
class WebViewDelegate: NSObject, UIWebViewDelegate {
var overlay: ProgressOverlay?
func webViewDidStartLoad(webView: UIWebView) {
// Here I want to access the 'view' of the outer class:
overlay = ProgressOverlay.cover(outerSelf.view)
}
func webViewDidFinishLoad(webView: UIWebView) {
overlay?.remove()
}
}
}
当然,您可以使用其他答案中建议的多种方法中的任何一种来解决缺少的outerSelf
功能,但这个示例实际上表明这是一个易于区分的代码段,可以被隔离。考虑以下替代方案:
class CustomSectionContentController : UIViewController {
@IBOutlet weak var webView: UIWebView!
lazy var webViewDelegate: ProgressOverlayWebViewDelegate =
ProgressOverlayWebViewDelegate(view: self.view)
override func viewDidLoad() {
super.viewDidLoad()
webView.delegate = webViewDelegate
}
}
class ProgressOverlayWebViewDelegate: NSObject, UIWebViewDelegate {
let view: UIView
init(view: UIView) {
self.view = view
}
var overlay: ProgressOverlay?
func webViewDidStartLoad(webView: UIWebView) {
overlay = ProgressOverlay.cover(view)
}
func webViewDidFinishLoad(webView: UIWebView) {
overlay?.remove()
}
}
看到区别?我们的控制器现在根本不处理WebView委托的问题区域。我们现在也有一个孤立的通用ProgressOverlayWebViewDelegate
,它对使用它的控制器一无所知。这意味着我们可以在其他控制器中重用此委托。
您可能一开始并不相信,但事实证明上述方法适用于涉及内部类的所有方案。隔离关注是一般抽象和编程良好实践的基石,因此每当遇到这种问题时,都会重新考虑。
答案 3 :(得分:2)
没有,并且在Swift中有类似的功能,你需要对其进行硬编码。
class Outer {
var value = 0
init(_ value: Int) {
self.value = value
}
func inner() -> Inner {
return Inner(self)
}
class Inner {
let outer: Outer
var value = 1
init(_ outer: Outer) {
self.outer = outer
}
func doSomething() {
print("Outer ", outer.value, " Inner ", value)
}
}
}
let i1 = Outer(1).inner()
i1.doSomething() // Outer 1 Inner 1
let i2 = Outer(2).inner()
i2.doSomething() // Outer 2 Inner 1
答案 4 :(得分:1)
你可以解决这个问题:
class Outer {
let value = ""
class Inner {
func foo(outer: Outer) {
let bar = outer.value
}
}
}
或者,不是将Outer
实例传递给foo
方法,而是将其传递给Inner
的初始值设定项。但是如果Inner
是enum
,那么这个技巧将不起作用,因为Swift enum
不能具有属性(除了关联值,它们就像属性一样)。
这种解决方法相当于Java对内部类隐式执行的操作,以避免给您带来传递参数和显式引用它的繁琐工作。
IMO Java内部类功能的基本原理类似于闭包的基本原理:该功能允许代码隐式使用环境中的变量(在这种情况下,环境是Outer
类实例)。我不知道为什么斯威夫特缺乏内部阶级。如果Swift被增强以执行内部类,则必须更改许多现有的Swift代码以将static
放在类声明之前。值得,IMO。
答案 5 :(得分:0)
好吧,你可以使用继承,这样你就可以使用外部作为内部的超类。
class Outer {
let value = ""
class Inner: Outer {
func foo() {
let bar = value //value is now accessable as it has internal access from the superclass
}
}
}
答案 6 :(得分:0)
如果您有许多内部类并且想要编写更少的代码行,那么您可以使用初始化程序创建基类,该初始化程序接受Outer
实例并从中继承所有内部类:
class Outer {
func testInner() {
print("test")
}
class InnerBase {
let outer: Outer
init(outer: Outer) {
self.outer = outer
}
}
class Inner1: InnerBase {
func test() {
outer.testInner()
}
}
class Inner2: InnerBase {
func test() {
outer.testInner()
}
}
func test() {
Inner1(outer: self).test()
Inner2(outer: self).test()
}
}
Outer().test()
答案 7 :(得分:-2)
这将违背面向对象编程的概念。内部类的实例如何知道它所属的外部类的哪个实例?类是蓝图,而不是内存中的实际对象。因此,您可以将外部类的实例的引用传递给内部类中的构造函数/初始化器,以获取从内部实例到外部实例的引用。