简体   繁体   中英

Swift: How to compare Optional in “if” clause

I'm practising Swift by building trees with array.

I have a class Node. Each node has an ID and a parent ID. The parent ID could be nil, if the node is a top-level node. So I made parent ID Optional.

Then I manually (for testing purpose) created an array of nodes, which contains multiple trees. So there are multiple nodes with parent ID = nil.

Then I created a function which find nodes by their parent ID.

Compiler didn't complain. However when run in iPhone simulator (I tried to display the nodes in a tableview), a message displays at the if clause in the function :

fatal error: unexpectedly found nil while unwrapping an Optional value

Please help. Thanks.

Here is the code. (for my own habit I write ";" at the end of each line.)

class Node {
  var id:Int;
  var parent:Int!;
  init(id:Int, parent:Int!) {
    self.id = id;
    self.parent = parent;
  }
}

var allNodes = [
  Node(id:1, parent: nil),
  Node(id:2, parent: nil),
  Node(id:3, parent: 1),
  Node(id:4, parent: 1),
  Node(id:5, parent: 2),
  Node(id:6, parent: 2),
  Node(id:7, parent: 2)
];

func findNodes(parent:Int!) -> [Node] {
  var arr:[Node] = [];
  for node in allNodes {
    if node.parent == parent! {
      // if I use "if node.parent == parent" without the "!" it gives me the same error
      arr.append(node);
    }
  }
  return arr;
}

let nodes = self.findNodes(nil);
// called in tableview functions.
// same message if I use findNodes(1).

Your find function is declared as

func findNodes(parent:Int!) -> [Node]

where the parameter is declared as implicitly unwrapped optional, so it will be unwrapped on each access. If you want to pass nil as parameter, then a "normal" optional makes more sense:

func findNodes(parent:Int?) -> [Node] {
    var arr:[Node] = [];
    for node in allNodes {
        if node.parent == parent {
            arr.append(node);
        }
    }
    return arr;
}

Note that you can simplify the code to (Swift 1.2):

func findNodes(parent:Int?) -> [Node] {
    return filter(allNodes) { $0.parent == parent };
}

It also would make more sense to declare the parent property in the Node class as optional if nil is an "expected" value:

class Node {
    var id : Int;
    var parent : Int?;
    init(id:Int, parent : Int?) {
        self.id = id;
        self.parent = parent;
    }
}

Or perhaps a (optional) pointer to the parent node:

var parent : Node?

but that is now unrelated to your question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM