去年,我成为了移动开发人员和功能性编程崇拜者。
在每个移动领域,都有一些组件具有生命周期方法,构成了应用程序的核心。以下将使用Android和Kotlin作为示例,但同样适用于iOS和Swift。
在Android中,有Activity
个生命周期方法,如onCreate()
。您还可以定义一个函数onButtonClicked()
,它将完全按照名称描述。
出于问题的目的,让我们说onCreate()
中定义的变量用于按钮点击处理程序onButtonClickedPrintMessageLength()
(这通常是案例 - onCreate()
基本上是Activity
的设置方法)。
示例类看起来像这样:
class ExampleActivity: Activity() {
var savedStateMessage: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
savedStateMessage = "Hello World!"
}
fun onButtonClickedPrintMessageLength() {
System.out.println(savedStateMessage?.length)
}
}
注意savedStateMessage
声明为String?
(可空字符串)并使用?.
(空安全呼叫)。这些是必需的,因为编译器无法保证在onCreate()
之前调用onButtonClickedPrintMessageLength()
。不过,作为开发人员,we know that onCreate
will always be called first * ** 。
我的问题是如何告诉编译器这些方法的保证顺序并消除空检查行为?
*我认为可以new
向上ExampleActivity
并直接调用onButtonClickedPrintMessageLength()
,从而避开Android框架和生命周期方法,但编译器/ JVM很可能在发生任何有趣的事情之前遇到错误。
**首先调用onCreate
的保证是由Android框架提供的,这是一个外部的事实来源,将来可能会以不同的方式破坏/运行。虽然看到所有Android应用程序都基于这一事实来源,但我相信它是值得信赖的。
答案 0 :(得分:6)
虽然这不能回答您的实际问题,但在Kotlin中,您可以使用lateinit
告诉编译器您将在以后初始化var
:
lateinit var savedStateMessage: String
如果在初始化之前尝试使用此变量,则会得到非常具体的UninitializedPropertyAccessException
。此功能在JUnit等用例中非常有用,您通常会在@Before
- 带注释的方法和Android Activity
中初始化变量,在这种情况下,您无权访问构造函数并初始化内容。 onCreate()
。
答案 1 :(得分:1)
如另一个答案中所述,lateinit
可用作将选项推迟到保证生命周期中的后续点。另一种方法是使用代理:
var savedStateMessage: String by Delegates.notNull()
这是等效的,因为如果在初始化之前访问变量,它将报告错误。
答案 2 :(得分:0)
在Swift中,您可以使用隐式解包的Optional
:
class Example: CustomStringConvertible {
var savedStateMessage: String! // implicitly-unwrapped Optional<String>
var description: String { return savedStateMessage }
init() {
savedStateMessage = "Hello World!"
}
}
print(Example()) // => "Hello World!\n"
通过在示例第二行的!
末尾使用运算符String
,您承诺在使用变量之前将设置该变量。这是在示例的init
方法中完成的。它仍然是Optional
,但代码可以将其视为String
,因为它会在每次使用前自动解包。您必须注意,当可能访问该变量时,该变量永远不会设置为nil
,或者可能会生成运行时异常。