When and how to use @noreturn attribute in Swift?
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!")
}
Is there any difference between never and void return type in swift? what is the use of never return type in practically?
Void
A return type that doesn’t return a value.
Never
Something that will never return.
Void vs Never
- Implementation: Void is a tuple, Never is an empty enum.
- Never informs the compiler that there is no need to return a value.
- Never is used in methods that will unconditionally throw an error or crash the system.
Convincing Swift that a function will never return, due to a thrown Exception
Swift's @noreturn
attribute marks functions and methods as not returning to their caller.
As probably the simplest example, the signature of the built-in function abort()
's is:
@noreturn func abort()
This gives the compiler all the information it needs. For example, the following will compile just fine:
func alwaysFail() -> Int {
abort()
}
Although alwaysFail()
theoretically returns an Int
, Swift knows that execution can't continue after abort()
is called.
The reason my original code didn't work is because NSException.raise
is a pre-Swift method, and therefore doesn't have the @noreturn
attribute. To easily solve this, I can either use abort()
:
func shouldBeOverridden() -> ReturnType {
println("Subclass has not implemented abstract method `shouldBeOverridden`!")
abort()
}
or, if I still want to use NSException
, I can define an extension with the proper attribute
extension NSException {
@noreturn func noReturnRaise() {
self.raise()
abort() // This will never run, but Swift will complain that the function isn't really @noreturn if I don't call a @noreturn function before execution finishes.
}
}
As a third option, I can just use a never-called abort()
after an NSException.raise()
to placate the compiler. The earlier option, using an extension
, is really just an abstraction for doing this:
func shouldBeOverridden() -> ReturnType {
let exception = NSException(
name: "Not implemented!",
reason: "A concrete subclass did not provide its own implementation of shouldBeOverridden()",
userInfo: nil
)
exception.raise()
abort() // never called
}
Related Topics
How to Tell If a Node Is on the Screen Spritekit Swift
How to Print a String from Plist Without "Optional"
Can't Hook Up an Outlet Collection in Xcode 6 Using Storyboard
Creating a Countableclosedrange<Character>
Expandable Sections Uitableview Indexpath Swift
Missing Return in a Function Expected to Return 'Double'
Is There a Writetofile Equivalent for Swift 3's 'Data' Type
Core Data: Failed to Load Model
How to Include Assets/Resources in a Swift Package Manager Library
Turn Off Xcode's Unused Variable Warnings While Typing
Background Request Not Execute Alamofire Swift
How to Convert a String to a Cstring in the Swift Language
Why Unsaferawpointer Shows Different Result When Function Signatures Differs in Swift
Converting a C-Style for Loop That Uses Division for the Step to Swift 3
Localizewithformat and Variadic Arguments in Swift
Compare App Versions After Update Using Decimals Like 2.5.2