Thomas
Thomas

Reputation: 33

Refresh a UITextView

I want to write some log text in a UITextview. e.g.: x image is loaded, y object created etc. My problem is: the UITextView doesn't refresh after a line is inserted. I think that when the insertion ends all new texts are displayed in the same time.

append = [@"" stringByAppendingFormat:@"\n%@ file is dowloading...", refreshName]
logTextView.text = [logTextView.text stringByAppendingString: append];

After download I save the file and

append = [@"" stringByAppendingFormat:@"\n%@ file saved", refreshName];
logTextView.text = [logTextView.text stringByAppendingString: append];

I tried

[logTextView setNeedsDisplay]

or

[logTextView performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:YES];

but it didn't work :(

Session would be:

  1. Insert new line to textview (downloading)
  2. Show this text
  3. Download file (few seconds)
  4. Insert new line to the UITextView (download finished)
  5. Show the text

What it happens is:

  1. Download the file (few sec.)
  2. UITextView show lines (downloadig, download finished)

Upvotes: 2

Views: 4766

Answers (1)

David Hoerl
David Hoerl

Reputation: 41642

The text will only update the next time through the main thread's runloop. If you have a long running task on the main loop, and it keeps writing to the textView, then nothing is going to get displayed before your task ends.

I can think of a few ways to fix this:

  • run the big task on the normal dispatch queue, and message back to the textView using dispatch_async(dispatch_get_main_queue(), append this new text); The idea is your task is performed on a secondary thread (so it cannot directly message the UI) but updates the UI by sending short blocks to the main queue.

  • break your big task into chunks, each of which can be initiated by a method. In this case you do the first one on the main queue, then dispatch a block to the main queue with the updated UITextView text, and following that the next chunk of work to be done. That is:

    dispatch_async(dispatch_get_main_queue(), ^ { update textView text; [self doTask1:maybeSomeDictionary]; }

when doTask1 completes, its dispatches the next block:

dispatch_async(dispatch_get_main_queue(), ^
{
    update textView text again;
    [self doTask2:maybeSomeDictionary];
}

When the final task finishes then you're done.

Upvotes: 1

Related Questions