xpg934
xpg934

Reputation: 81

Monotouch random crash in native code using UITableView

Please help me, what am I doing wrong.

I use BubbleCell and BubbleElement from the examples. For unknown reasons, the application sometimes crashes in native code. I try out a little bit to correct the situation if I do not use DequeueReusableCell, and always create a new BubbleCell. Also, the problem disappears if the constructor BubbleElement to pass a string constant as the caption, not the object field.

Stacktrace: http://pastebin.com/KAYzpHDk


The problem is deeper than it seems. Your suggestion doesn't help, the application still crashes.

I made a separate project, leaving it a minimum of code necessary to show the problem. The problem is somehow related to System.Json... maybe.

Here is an archive of the project: https://dl.dropbox.com/u/63074515/BubbleNativeCrash.zip

The sequence of actions: 1) open the project 2) compile and run the emulator without debugging (configuration Debug|iPhoneSimulator) 3) click horse1 in the first view 4) in the list that appears, scroll whole items a few times up and down 5) in my case at this stage we crash... (stack trace: http://pastebin.com/KAYzpHDk)

If not immediately fail, you can return to the contact list, and vice versa, or even once a few times. How quickly will fail depends on the number of messages in the chat.

Now the fun part. The problem disappears completely (or I can not repeat it in a reasonable time) if in ChatViewController.cs comment the line 406 and uncomment line 407:

// string messageText = msg.MessageText ?? string.Empty;
string messageText = "Hello, World!!!";

That is, make a constant string passed into BubbleElement constructor. After that, the problem does not repeat, I think.

I tried to leave everything as is, but remove the work with the Json - the problem disappears. The problem in only when BubbleElement takes a string read from the JsonValue (IM\IMMessage.cs at line 36). Even if there is, in IMMessage.cs, to set a constant string for MessageText - the problem disappears.

What am I doing wrong? :)

p.s. Sorry for my english... it powered by google translate.

Upvotes: 2

Views: 382

Answers (1)

poupou
poupou

Reputation: 43553

You do not keep any reference to the managed instance you return from GetCell. As such the GC can (and will) collect the managed instance once the method returns while the native instance will continue to live (since it's referenced inside iOS).

This works fine when you use UITableViewCell since all the state is kept inside the native instance. However this is not the case if you inherit from it and add your own managed fields. In such cases you won't be able to access the managed state since it won't exists (the instance you'll have won't be the one you created).

The easy way to solve this is to keep a reference to the BubbleCell you create, e.g. in a list, so the GC won't collect them.

    static List<BubbleCell> cell_cache = new List<BubbleCell> ();

    public override UITableViewCell GetCell(UITableView tableView)
    {
        var cell = tableView.DequeueReusableCell(isLeft ? BubbleCell.KeyLeft : BubbleCell.KeyRight) as BubbleCell;
        if (cell == null) {
            cell = new BubbleCell(isLeft);
            cells_cache.Add (cell);
        }
        cell.Update(Caption);
        return cell;
    }

Do not forget to clear the list once the cells are not needed anymore (e.g. when closing the UITableView).

UPDATE FROM EXTRA INFORMATION

The cell_cache must be static or it won't help (my mistake, fixed above) to keep references alive. But, as you found out, it's not the fix for this case (source shows the cells can be reused).

OTOH the issue is not related to using JSON. Using the same string messages (e.g. from an array) results in the same crash. That's a bit weird and I'll investgate this further...

FINAL UPDATE

It turns out the calls to CreateResizableImage can hit an iOS bug. The workaround is to use the older StretchableImage API. The issue was (re)submitted to Apple.

Upvotes: 1

Related Questions