Reputation: 478
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).
Upvotes: 2
Views: 264
Reputation: 540145
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.
Upvotes: 4