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
}