-5

I inherited an iOS app that is crashing at this line (unexpected nil). What is your best interpretation of what is going on here?

indexPath.row.number == selectedItem ? cell.deselectStyle() : cell.dedeselectStyle()

The cell.deselectStyle() and cell.dedeselectStyle() functions don't return anything. I can't seem to find any information on what is going on here. selectedItem is a NSNumber!.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
Nils Guillermin
  • 1,867
  • 3
  • 21
  • 51
  • `selectedItem` is nil that's why it is crashing – NSDmitry May 16 '17 at 14:13
  • I get that, I'm just wondering what is the point of everything after the `?`. – Nils Guillermin May 16 '17 at 14:13
  • `if (indexPath.row.number == selectedItem){cell.deselectStyle()} else{cell.dedeselectStyle()}` It doesn't matter if they return something. It's not `if (selectedItem){indexPath.row.number = cell.deselectStyle()} else{indexPath.row.number = cell.dedeselectStyle()}` as you seem to misderstand – Larme May 16 '17 at 14:15
  • If the condition is true, this one `cell.deselectStyle()` is called. If it is false this `cell.dedeselectStyle()` is called. – Praveen Kumar May 16 '17 at 14:15
  • Oh, ok, I see it now. – Nils Guillermin May 16 '17 at 14:15
  • I edited the question as I found it misleading. C and D are different in your question example. – Bathsheba May 16 '17 at 14:15
  • Check this https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/BasicOperators.html#//apple_ref/doc/uid/TP40014097-CH6-ID71 – Axel Guilmin May 16 '17 at 14:22

4 Answers4

0

Probably The reason the crash is that selectedItem is nil; I think you misunderstand the difference between the ? for optionals and the ? for implementing the ternary operator.

The ternary operator has nothing to do with -implicitly- checking if the value is nil, you might need to implement a guard statement or if let (optional binding) before the step of doing the ternary operator comparison.

It should be similar to:

if let selectedItem = selectedItem {
    indexPath.row.number == selectedItem ? cell.deselectStyle() : cell.dedeselectStyle()
} else {
    print("selectedItem is nil!")
}

Or, if an early return required:

guard let selectedItem = selectedItem else {
    print("selectedItem is nil!")
    return
}

indexPath.row.number == selectedItem ? cell.deselectStyle() : cell.dedeselectStyle()

To make it more clear to you, check the following code snippet:

let nilValue: String! = nil

if nilValue == "test" { }
// fatal error: unexpectedly found nil while unwrapping an Optional value

// OR
let isValueTest: Bool = (nilValue == "test") ? true : false
// fatal error: unexpectedly found nil while unwrapping an Optional value

That's why you should unwrap the value before accessing it.

Ahmad F
  • 30,560
  • 17
  • 97
  • 143
0

NSNumber could be nil leading to a crash if you try to access it. Add a guard to check that is not nil.

guard let s = selectedItem?.intValue else {
    cell.dedeselectStyle
    return
}

indexPath.row == s ? cell.deselectStyle() : cell.dedeselectStyle()

I've assumed it's safe to assume the cell is not selected if the NSNumber is nil, however you should really check the logic in your code to be sure.

tanz
  • 2,557
  • 20
  • 31
0

This is a conditional statement. Think of it like an if statement:

if indexPath.row.number == selectedItem {
    cell.deselectStyle()
} else {
    cell.dedeselectStyle()
}

If the condition is true, the code between ? and : will be executed. If not, the code after the : will be called. You should know that the ? has nothing to do with Optionals.

In your case, selectedItem seems to be nil. Therefore, you need to either only execute the code if selectedItem is not nil, you could use an if let statement:

if let selectedItem = selectedItem {
    indexPath.row.number == selectedItem ? cell.deselectStyle() : cell.dedeselectStyle()
}

Or, you could insert a default value that will be used instead of selectedItem if it is nil:

indexPath.row.number == (selectedItem ?? false) ? cell.deselectStyle() : cell.dedeselectStyle()

The code above will use either the value of selectedItem, or false, if selectedItem is nil. You can leave out the parentheses, I just put them there for better visualization.

I hope this helps :)

LinusGeffarth
  • 27,197
  • 29
  • 120
  • 174
0

to better understand it, play in your Playground

func f0() -> Int { print(0); return 0 }
func f1() -> Int { print(1); return 1 }
func fa() -> String { print("a"); return "a" }

[true, false, true, true].forEach {
    $0 ? f0() : f1() // warning: expression of type 'Int' is unused
}

[true, false, true, true].forEach {
   _ = $0 ? f0() : f1() // OK
}

[true, false, true, true].forEach {
    $0 ? f0() : fa() // error: result values in '? :' expression have mismatching types 'Int' and 'String'
}

[true, false, true, true].forEach {
    _ = $0 ? ( 1 == f0()) : ( "A" == fa()) // OK
}
user3441734
  • 16,722
  • 2
  • 40
  • 59