I read the code block enclosed in curly braces after the keyword else
in the context of a guard-else
flow, must call a function marked with the noreturn
attribute or transfer control using return
, break
, continue
or throw
.
The last part is quite clear, while I don't understand well the first.
First of all, any function returns something (an empty tuple at least) even if you don't declare any return type. Secondly, when can we use a noreturn
function? Are the docs suggesting some core, built-in methods are marked with noreturn
?
The else clause of a guard statement is required, and must either call a function marked with the noreturn attribute or transfer program control outside the guard statement’s enclosing scope using one of the following statements:
return break continue throw
Here is the source.
First of all, any function returns something (an empty tuple at least) even if you don't declare any return type.
(@noreturn is obsolete; see Swift 3 Update below.)
No, there are functions which terminate the process immediately
and do not return to the caller. These are marked in Swift
with @noreturn
, such as
@noreturn public func fatalError(@autoclosure message: () -> String = default, file: StaticString = #file, line: UInt = #line)
@noreturn public func preconditionFailure(@autoclosure message: () -> String = default, file: StaticString = #file, line: UInt = #line)
@noreturn public func abort()
@noreturn public func exit(_: Int32)
and there may be more.
(Remark: Similar annotations exist in other programming languages
or compilers, such as [[noreturn]]
in C++11, __attribute__((noreturn))
as a GCC extension, or _Noreturn
for the
Clang compiler.)
You can mark your own function with @noreturn
if it also terminates
the process unconditionally, e.g. by calling one of the built-in functions, such as
@noreturn func myFatalError() {
// Do something else and then ...
fatalError("Something went wrong!")
}
Now you can use your function in the else clause of a guard
statement:
guard let n = Int("1234") else { myFatalError() }
@noreturn
functions can also be used to mark cases that "should not
occur" and indicate a programming error. A simple example
(an extract from Missing return UITableViewCell):
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: MyTableViewCell
switch (indexPath.row) {
case 0:
cell = tableView.dequeueReusableCellWithIdentifier("cell0", forIndexPath: indexPath) as! MyTableViewCell
cell.backgroundColor = UIColor.greenColor()
case 1:
cell = tableView.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as! MyTableViewCell
cell.backgroundColor = UIColor.redColor()
default:
myFatalError()
}
// Setup other cell properties ...
return cell
}
Without myFatalError()
marked as @noreturn
, the compiler would
complain about a missing return in the default case.
Update: In Swift 3 (Xcode 8 beta 6) the @noreturn
attribute
has been replaced by a Never
return type, so the above example
would now be written as
func myFatalError() -> Never {
// Do something else and then ...
fatalError("Something went wrong!")
}