2
votes

If I need to return something that can be nil, how should I decide if my func should return optional or implicitly unwrapped optional? I have seen Swift methods of either version, I am curious what drives the decision to return an optional versus an implicitly unwrapped optional from a function/method because it seems like either way you still need to check for non-nil before you can use it.

For example, SpriteKit's SKNode uses implicitly unwrapped heavily (partial version shown below)

class SKNode : UIResponder, NSCopying, NSCoding {

    ...

    /**
     The parent of the node.

     If this is nil the node has not been added to another group and is thus the root node of its own graph.
     */
    var parent: SKNode! { get }

    /**
     The children of this node.

     */
    var children: AnyObject[]! { get }

    /**
     The client assignable name.

     In general, this should be unique among peers in the scene graph.
     */
    var name: String!

    /**
     The scene that the node is currently in.
     */
    var scene: SKScene! { get }

    /**
     Physics body attached to the node, with synchronized scale, rotation, and position
     */
    var physicsBody: SKPhysicsBody!

    /**
     An optional dictionary that can be used to hold user data pretaining to the node. Defaults to nil. 
     */
    var userData: NSMutableDictionary!

    /**
     Kinematic constraints, used in IK solving
     */
    var reachConstraints: SKReachConstraints!

    /**
     Optional array of SKConstraints
     Constraints are evaluated each frame after actions and physics.
     The node's transform will be changed to staisfy the constarint.
     */
    var constraints: AnyObject[]!

    /**
     Sets both the x & y scale

     @param scale the uniform scale to set.
     */
    func setScale(scale: CGFloat)

    /**
     Adds a node as a child node of this node

     The added node must not have a parent.

     @param node the child node to add.
     */
    func addChild(node: SKNode!)

    func insertChild(node: SKNode!, atIndex index: Int)

    func removeChildrenInArray(nodes: AnyObject[]!)
    func removeAllChildren()

    func removeFromParent()

    func childNodeWithName(name: String!) -> SKNode!
    func enumerateChildNodesWithName(name: String!, usingBlock block: ((SKNode!, CMutablePointer<ObjCBool>) -> Void)!)

    /* Returns true if the specified parent is in this node's chain of parents */

    func inParentHierarchy(parent: SKNode!) -> Bool

    func runAction(action: SKAction!)
    func runAction(action: SKAction!, completion block: (() -> Void)!)
    func runAction(action: SKAction!, withKey key: String!)

    func hasActions() -> Bool
    func actionForKey(key: String!) -> SKAction!

    func removeActionForKey(key: String!)
    func removeAllActions()

    func containsPoint(p: CGPoint) -> Bool
    func nodeAtPoint(p: CGPoint) -> SKNode!
    func nodesAtPoint(p: CGPoint) -> AnyObject[]!

    func convertPoint(point: CGPoint, fromNode node: SKNode!) -> CGPoint
    func convertPoint(point: CGPoint, toNode node: SKNode!) -> CGPoint

    /* Returns true if the bounds of this node intersects with the transformed bounds of the other node, otherwise false */

    func intersectsNode(node: SKNode!) -> Bool
}
3

3 Answers

3
votes

It's probably too early to have strict best practices for swift, but here's my opinion. In general implicitly unwrapped optionals should be used for a few cases such as outlets, properties that are nil until initialization and return values from Objective-C functions, otherwise a regular optional should be used.

If you are creating a function that will return a value or nil, do the other programmers interacting with your code a favor and make the return value an optional.

2
votes

I feel like Swift is a bit too young at the moment for this kind of advice, so take any with a grain of salt. And in the future who knows, maybe a new feature will come to Swift that changes how everyone writes Swift code.

That being said, here are my thoughts on this topic:

In native Swift code you should stay away from implicitly unwrapped optionals as much as you can. If your function may return nil for any reason, then the return type should be Optional, which tells the receiver that they can expect nil to be returned.

Returning an implicitly unwrapped optional from a native Swift function currently doesn't give you much information. To me it says "This return value should never be nil". But in that case, why does it need to be an Optional at all?

Edit: Regarding your posted code, the only reason that code returns implicitly unwrapped optionals is because it is translated from ObjC.

0
votes

In my opinion, for old framework the reason apple using implicitly unwrapped optionals is to provide almost the same usage and behaviours as Obj-C.