Farros Mufid
Farros Mufid

Reputation: 39

Unexpectedly found nil while unwrapping an Optional value (Cannot figure out which part)

I'm new to Swift and I cannot figure out which optional variable that I unwrapped and I assigned nil to it, I tried to debug it on Playground but it won't let me step through the code.

Fatal error: Unexpectedly found nil while unwrapping an Optional value

public class ListNode {
    public var val: Int
    public var next: ListNode?
    public init() { self.val = 0; self.next = nil; }
    public init(_ val: Int) { self.val = val; self.next = nil; }
    public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; }
}
class Solution {
    func addTwoNumbers(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? {
        let result = ListNode()
        var resultTail = result
        var carry: Int = 0
        var out: Int = 0
        var val1: Int = 0
        var val2: Int = 0

        var head1: ListNode? = l1
        var head2: ListNode? = l2

        while (l1 != nil || l2 != nil || carry != 0) {

            val1 = head1 != nil ? head1!.val : 0
            val2 = head2 != nil ? head2!.val : 0

            out = (val1 + val2 + carry) % 10
            carry = (val1 + val2 + carry) / 10

            resultTail.next = ListNode(out)
            resultTail = resultTail.next!

            head1 = head1?.next!
            head2 = head2?.next!

        }
        return result.next!
    }
}
let node3 = ListNode(3)
let node2 = ListNode(4, node3)
let node1 = ListNode(2, node2)

let node3a = ListNode(5)
let node2a = ListNode(6, node3a)
let node1a = ListNode(4, node2a)

let solution = Solution().addTwoNumbers(node1, node1a)

Best regards, Farros

Upvotes: 1

Views: 156

Answers (1)

Paulw11
Paulw11

Reputation: 114856

If you search for the "unexpectedly found nil" error message you will find several questions and answers that explain what this means and suggest debugging techniques.

While the root cause of this error can be subtle, the trigger for the exception is force unwrapping an optional that is nil or referencing an implicitly unwrapped optional that is nil.

You don't have a lot of code here, so it isn't hard to find where you do one of those things;

You force unwrap in your ternary operator, that is after a check for nil, so that won't crash

You force unwrap resultTail.next and result.next but you have assigned values in those cases, so that won't cause the crash.

The last place is where you force unwrap head1.next and head2.next at the bottom of your while loop. This is a mistake because you know that next will eventually be nil at the end of your list.

Simply removing the ! will eliminate the exception, but introduce a new bug because your while loop condition tests the initial parameters l1 and l2 whose values never change. You risk an infinite loop. I think you meant to reference head1 and head2.

You should try and eliminate all force unwraps and this isn't too hard:

  • Use the nil coalescing operator instead of the ternary
  • head1 and head2 are optional, so there is no need to force unwrap next
  • Your function returns an optional, so we can declare resultTail as an optional and use conditional unwrapping or no unwrapping
class Solution {
    func addTwoNumbers(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? {
        let result = ListNode()
        var resultTail: ListNode? = result
        var carry = 0

        var head1 = l1
        var head2 = l2

        while (head1 != nil || head2 != nil || carry != 0) {

            let val1 = head1?.val ?? 0
            let val2 = head2?.val ?? 0

            let sum = val1 + val2 + carry

            let out = sum % 10
            carry = sum / 10

            resultTail?.next = ListNode(out)
            resultTail = resultTail?.next

            head1 = head1?.next
            head2 = head2?.next

        }
        return result.next
    }
}

Note that idiomatic Swift you only explicitly type variables where the correct type cannot be inferred automatically by the compiler or you need a different type to that which the compiler will infer.

You can also simplify and clarify your ListNode by using named parameters with defaults in a single init

public class ListNode {
    public var val: Int
    public var next: ListNode?
    public init(val: Int = 0, next: ListNode? = nil) { 
        self.val = val
        self.next = next
    }
}

class Solution {
    func addTwoNumbers(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? {
        let result = ListNode()
        var resultTail: ListNode? = result
        var carry = 0

        var head1 = l1
        var head2 = l2

        while (head1 != nil || head2 != nil || carry != 0) {

            let val1 = head1?.val ?? 0
            let val2 = head2?.val ?? 0

            let sum = val1 + val2 + carry
            let out = sum % 10
            carry = sum / 10

            resultTail?.next = ListNode(val: out)
            resultTail = resultTail?.next

            head1 = head1?.next
            head2 = head2?.next
        }
        return result.next
    }
}

let node3 = ListNode(val:3)
let node2 = ListNode(val: 4, next: node3)
let node1 = ListNode(val: 2, next: node2)

let node3a = ListNode(val:5)
let node2a = ListNode(val: 6, next: node3a)
let node1a = ListNode(val: 4, next: node2a)

let solution = Solution().addTwoNumbers(node1, node1a)

Upvotes: 0

Related Questions