Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift - Editing UITextView from inside callback crashes app

I have the following code that makes a HTTP Request, then outputs the result to a UITextView:

@IBOutlet var echoLog: UITextView!

@IBAction func sendEcho(sender: AnyObject) {
    let callback = { (textString: String) -> Void in
        self.echoLog.text = textString // App crashes here :(
    }
    HTTPRequest("http://localhost/echo", ["echo": "Echo!"], callback)
}

But when I call sendEcho the app crashes with this error:

2014-07-28 20:58:22.218 AppName[10463:144343] *** Assertion failure in void _UIPerformResizeOfTextViewForTextContainer(NSLayoutManager *, UIView<NSTextContainerView> *, NSTextContainer *, NSUInteger)(), /SourceCache/UIFoundation_Sim/UIFoundation-364/UIFoundation/TextSystem/NSLayoutManager_Private.m:1547
2014-07-28 20:58:22.231 AppName[10463:144343] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Only run on the main thread!'
*** First throw call stack:
(
    0   CoreFoundation                      0x00496ca6 __exceptionPreprocess + 182
    1   libobjc.A.dylib                     0x01df08bf objc_exception_throw + 44
    2   CoreFoundation                      0x00496b3a +[NSException raise:format:arguments:] + 138
    3   Foundation                          0x00904d2e -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:] + 102
    4   UIFoundation                        0x03344072 -[NSLayoutManager(NSPrivate) _resizeTextViewForTextContainer:] + 418
    5   UIFoundation                        0x03343d6e -[NSLayoutManager(NSPrivate) _recalculateUsageForTextContainerAtIndex:] + 2017
    6   UIFoundation                        0x0337da43 -[NSLayoutManager textStorage:edited:range:changeInLength:invalidatedRange:] + 871
    7   UIFoundation                        0x0337db53 -[NSLayoutManager processEditingForTextStorage:edited:range:changeInLength:invalidatedRange:] + 85
    8   UIFoundation                        0x033a7a7b -[NSTextStorage _notifyEdited:range:changeInLength:invalidatedRange:] + 153
    9   UIFoundation                        0x033a759a -[NSTextStorage processEditing] + 458
    10  UIFoundation                        0x033a7124 -[NSTextStorage endEditing] + 80
    11  UIFoundation                        0x033a71af -[NSTextStorage coordinateEditing:] + 67
    12  UIKit                               0x014938ae -[UITextView setAttributedText:] + 250
    13  UIKit                               0x01499745 -[UITextView setText:] + 149
    14  AppName                            0x00036216 _TFFC8AppName19FirstViewController8sendEchoFS0_FPSs9AnyObject_T_U_FOS_9JSONValueT_ + 1350
    15  AppName                            0x0003525a _TPA__TFFC8AppName19FirstViewController8sendEchoFS0_FPSs9AnyObject_T_U_FOS_9JSONValueT_ + 106
    16  AppName                            0x0001de86 _TFF8AppName11HTTPRequestFTSSGVSs10DictionarySSPSs9AnyObject__FOS_9JSONValueT__T_U_FTGSQCSo6NSData_GSQCSo13NSURLResponse_GSQCSo7NSError__T_ + 1350
    17  AppName                            0x0001d0a4 _TPA__TFF8AppName11HTTPRequestFTSSGVSs10DictionarySSPSs9AnyObject__FOS_9JSONValueT__T_U_FTGSQCSo6NSData_GSQCSo13NSURLResponse_GSQCSo7NSError__T_ + 100
    18  AppName                            0x0001e289 _TTRXFo_oGSQCSo6NSData_oGSQCSo13NSURLResponse_oGSQCSo7NSError__dT__XFo_iTGSQS__GSQS0__GSQS1____iT__ + 41
    19  AppName                            0x0001d15a _TPA__TTRXFo_oGSQCSo6NSData_oGSQCSo13NSURLResponse_oGSQCSo7NSError__dT__XFo_iTGSQS__GSQS0__GSQS1____iT__ + 90
    20  AppName                            0x0001e2d7 _TTRXFo_iTGSQCSo6NSData_GSQCSo13NSURLResponse_GSQCSo7NSError___iT__XFo_oGSQS__oGSQS0__oGSQS1___dT__ + 55
    21  AppName                            0x0001d224 _TPA__TTRXFo_iTGSQCSo6NSData_GSQCSo13NSURLResponse_GSQCSo7NSError___iT__XFo_oGSQS__oGSQS0__oGSQS1___dT__ + 100
    22  AppName                            0x0001e36e _TTRXFo_oGSQCSo6NSData_oGSQCSo13NSURLResponse_oGSQCSo7NSError__dT__XFdCb_dGSQS__dGSQS0__dGSQS1___dT__ + 142
    23  CFNetwork                           0x02c36158 __49-[__NSCFLocalSessionTask _task_onqueue_didFinish]_block_invoke + 181
    24  Foundation                          0x0092da35 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    25  Foundation                          0x00854635 -[NSBlockOperation main] + 99
    26  Foundation                          0x00833a97 -[__NSOperationInternal _start:] + 700
    27  Foundation                          0x008337c9 -[NSOperation start] + 83
    28  Foundation                          0x00833613 __NSOQSchedule_f + 237
    29  libdispatch.dylib                   0x022ef3ff _dispatch_client_callout + 14
    30  libdispatch.dylib                   0x022d8578 _dispatch_queue_drain + 1424
    31  libdispatch.dylib                   0x022d7f90 _dispatch_queue_invoke + 142
    32  libdispatch.dylib                   0x022d9e06 _dispatch_root_queue_drain + 312
    33  libdispatch.dylib                   0x022dae67 _dispatch_worker_thread2 + 45
    34  libsystem_pthread.dylib             0x0263fdab _pthread_wqthread + 336
    35  libsystem_pthread.dylib             0x02643cce start_wqthread + 30
)
    libc++abi.dylib: terminating with uncaught exception of type NSException

Thanks in advance!

like image 542
Luc Avatar asked Mar 16 '26 15:03

Luc


1 Answers

It looks like your problem is that you are not on the mainThread, by the second line in the trace.

You are probably still running code in the background, due to the nature of HTTPRequest asynchronous handling of data... that's fine. You just need to get to the main thread, after all is said and done.

Here's how to probably fix it...

@IBAction func sendEcho(sender: AnyObject)
{
    let callback = {(textString: String) in 
        dispatch_sync(dispatch_get_main_queue())
        {
            self.echoLog.text = textString //Yay!
        }
    }
    HTTPRequest("http://localhost/echo", ["echo": "Echo!"], callback)
}

Reminder time UI updates should only be performed on the mainThread. Simply because doing so provides high priority for this thing to occur. Usually when you try to do UI updates on a background thread, you will see a delay between when the code is executed and when you see results. In this case, an Assertion failure (I like that). If you do not know if you are on the main thread, you can check it out by doing NSThread.isMainThread() which returns a bool.

Warning If you are already on the main thread while calling dispatch_sync(dispatch_get_main_queue()) {...} your app will freeze up, so make sure you know what thread you are on...

like image 189
Ethan Avatar answered Mar 19 '26 06:03

Ethan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!