2

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?) {
      super.awakeWithContext(context)
      loadTableData()
  }

  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?

Edit:

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.

Oleksandr Skrypnyk
  • 2,762
  • 1
  • 20
  • 25
  • Have you created a table row controller (subclass of NSObject) and made that the class of your table row? – John Rogers Apr 29 '15 at 23:13
  • Yes, I have a custom table row controller, but it doesn't matter if I'm using it or not - always the same exception. – Oleksandr Skrypnyk Apr 29 '15 at 23:24
  • If you look in the stack trace, it's crashing right after "setRowTypes:". This is hinting to me that perhaps your row type string is incorrect? Seems like it can't find a row type with that identifier. Are you 100% sure that "Row Controller Identifier" in the attributes inspector of your table cell is "MyTableRow"? Did you also know that you can set the number of rows from the attributes inspector of your table in interface builder? – John Rogers Apr 29 '15 at 23:27
  • After reading the question, I have the same suspicions as John. It seems that the row type isn't being resolved correctly. – Mike Swanson Apr 29 '15 at 23:35
  • Row type and row controller identifier are totally match. Just checked using a new controller - still the same. – Oleksandr Skrypnyk Apr 29 '15 at 23:39
  • The code you provided is correct, so error is in the other place. One more idea - verify your `MainInterfaceController `'s class and identifier in storyboard. – onegray Apr 30 '15 at 08:04
  • I have this bug too. Do you remember the third-party library that did the funny swizzling? – Gwendal Roué Sep 22 '16 at 14:59
  • @GwendalRoué I'm not sure we're talking about the same library, because it's not even supported anymore. http://web.archive.org/web/20130622120954/http://www.stoeger-it.de/en/SecureIncrementalStore/ – Oleksandr Skrypnyk Sep 22 '16 at 16:17
  • OK Oleksandr. Thanks for your reply! – Gwendal Roué Sep 22 '16 at 20:04

3 Answers3

1

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

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

enter image description here

Beau Nouvelle
  • 6,962
  • 3
  • 39
  • 54
0

Make sure you choose the right module (its right under the class in IB)

Bjorn Reppen
  • 22,007
  • 9
  • 64
  • 88
rgreso
  • 496
  • 1
  • 7
  • 19
0

This works for me.

  1. Go to storyboard
  2. Show the Identify Inspector
  3. For each row controller, add a class implementation (even the class is as simple as a dummy subclass of NSObject)
Harry Ng
  • 1,070
  • 8
  • 20