The WatchKit application crashes when you try to set the number of rows in a table


So, I have a WatchKit app with WKInterfaceTable in a main interface controller, outlet to the Storyboard is set so it's not nil, table row identifier is also set and matches the string, I'm using in setNumberOfRows:withRowType: method.

Here is a simplified code of the interface controller for better understanding:

class MainInterfaceController: WKInterfaceController {
  @IBOutlet weak var table: WKInterfaceTable!

  override func awakeWithContext(context: AnyObject?) {

  private func loadTableData() {
    table.setNumberOfRows(5, withRowType: "MyTableRow")

When the method setNumberOfRows:withRowType: is called, I'm getting an exception of type NSRangeException:

*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM replaceObjectAtIndex:withObject:]: index 0 beyond bounds for empty array'

This is totally not related to some array and can happen even if I'm using just a plain integer as a parameter for number of rows, like in the code above.

Here is a stack trace of this method and an arrow pointed to the last successful step, after which the app throwing an exception:

WatchKit`-[WKInterfaceTable setNumberOfRows:withRowType:]:
    0x10e63e0ef <+0>:   pushq  %rbp
    0x10e63e0f0 <+1>:   movq   %rsp, %rbp
    0x10e63e0f3 <+4>:   pushq  %r15
    0x10e63e0f5 <+6>:   pushq  %r14
    0x10e63e0f7 <+8>:   pushq  %r13
    0x10e63e0f9 <+10>:  pushq  %r12
    0x10e63e0fb <+12>:  pushq  %rbx
    0x10e63e0fc <+13>:  pushq  %rax
    0x10e63e0fd <+14>:  movq   %rdx, %r12
    0x10e63e100 <+17>:  movq   %rdi, -0x30(%rbp)
    0x10e63e104 <+21>:  movq   %rcx, %rdi
    0x10e63e107 <+24>:  callq  *0x1800b(%rip)            ; (void *)0x000000010cc03930: objc_retain
    0x10e63e10d <+30>:  movq   %rax, %r15
    0x10e63e110 <+33>:  movq   0x28461(%rip), %rdi       ; (void *)0x000000010d2004e8: NSMutableArray
    0x10e63e117 <+40>:  movq   0x277aa(%rip), %rsi       ; "array"
    0x10e63e11e <+47>:  callq  *0x17fe4(%rip)            ; (void *)0x000000010cc06000: objc_msgSend
    0x10e63e124 <+53>:  movq   %rax, %rdi
    0x10e63e127 <+56>:  callq  0x10e63ee6e               ; symbol stub for: objc_retainAutoreleasedReturnValue
    0x10e63e12c <+61>:  movq   %rax, %rbx
    0x10e63e12f <+64>:  testq  %r12, %r12
    0x10e63e132 <+67>:  jle    0x10e63e158               ; <+105>
    0x10e63e134 <+69>:  movq   0x28205(%rip), %r13       ; "setObject:atIndexedSubscript:"
    0x10e63e13b <+76>:  xorl   %r14d, %r14d
    0x10e63e13e <+79>:  movq   %rbx, %rdi
    0x10e63e141 <+82>:  movq   %r13, %rsi
    0x10e63e144 <+85>:  movq   %r15, %rdx
    0x10e63e147 <+88>:  movq   %r14, %rcx
    0x10e63e14a <+91>:  callq  *0x17fb8(%rip)            ; (void *)0x000000010cc06000: objc_msgSend
->  0x10e63e150 <+97>:  incq   %r14
    0x10e63e153 <+100>: cmpq   %r14, %r12
    0x10e63e156 <+103>: jne    0x10e63e13e               ; <+79>
    0x10e63e158 <+105>: movq   0x281e9(%rip), %rsi       ; "setRowTypes:"
    0x10e63e15f <+112>: movq   -0x30(%rbp), %rdi
    0x10e63e163 <+116>: movq   %rbx, %rdx
    0x10e63e166 <+119>: callq  *0x17f9c(%rip)            ; (void *)0x000000010cc06000: objc_msgSend
    0x10e63e16c <+125>: movq   0x17f9d(%rip), %r14       ; (void *)0x000000010cc039b0: objc_release
    0x10e63e173 <+132>: movq   %rbx, %rdi
    0x10e63e176 <+135>: callq  *%r14
    0x10e63e179 <+138>: movq   %r15, %rdi
    0x10e63e17c <+141>: movq   %r14, %rax
    0x10e63e17f <+144>: addq   $0x8, %rsp
    0x10e63e183 <+148>: popq   %rbx
    0x10e63e184 <+149>: popq   %r12
    0x10e63e186 <+151>: popq   %r13
    0x10e63e188 <+153>: popq   %r14
    0x10e63e18a <+155>: popq   %r15
    0x10e63e18c <+157>: popq   %rbp
    0x10e63e18d <+158>: jmpq   *%rax

Is there a way to find out why or where it happens at all?


I've tried to use the setRowTypes: and got this trace:

    0x10ccb6fb9 <+735>:  movq   0x277f0(%rip), %rsi       ; "addObject:"
    0x10ccb6fc0 <+742>:  movq   %r14, %rdx
    0x10ccb6fc3 <+745>:  callq  *%r13
    0x10ccb6fc6 <+748>:  movq   %r14, %rdi
    0x10ccb6fc9 <+751>:  movq   0x18140(%rip), %rax       ; (void *)0x000000010b27c9b0: objc_release
    0x10ccb6fd0 <+758>:  movq   %r15, %r14
    0x10ccb6fd3 <+761>:  movq   %rax, %rbx
    0x10ccb6fd6 <+764>:  callq  *%rbx
    0x10ccb6fd8 <+766>:  movq   -0x70(%rbp), %rdi
    0x10ccb6fdc <+770>:  callq  *%rbx
    0x10ccb6fde <+772>:  movq   -0x68(%rbp), %rdi
    0x10ccb6fe2 <+776>:  callq  *%rbx
    0x10ccb6fe4 <+778>:  movq   -0x58(%rbp), %rdi
    0x10ccb6fe8 <+782>:  callq  *%rbx
    0x10ccb6fea <+784>:  movq   -0x50(%rbp), %rdi
    0x10ccb6fee <+788>:  callq  *%rbx
    0x10ccb6ff0 <+790>:  movq   -0x88(%rbp), %rdi
    0x10ccb6ff7 <+797>:  movq   0x28342(%rip), %rsi       ; "setObject:atIndexedSubscript:"
    0x10ccb6ffe <+804>:  movq   %r14, %rdx
    0x10ccb7001 <+807>:  movq   %r12, %rcx
    0x10ccb7004 <+810>:  callq  *%r13
->  0x10ccb7007 <+813>:  movq   %r12, %r13

As before it crashes after calling setObject:atIndexedSubscript:, so nothing relative to row type string.

Edit 2:

Sorry guys, I found what was wrong: it was a closed-source 3rd-party library, which swizzling NSArray subscripting methods to objectAtIndex: / replaceObjectAtIndex:withObject:, which is totally wrong. Strange, that I didn't had those use cases before.

Make sure you have set the row type in interface builder, and it matches the one in your code.

table.setNumberOfRows(5, withRowType: "DetailsRow")