I have a custom tableview cell, which contains some object UIImageView, UILabel, and a UITextView. All object, except the UITextView works fine, but when I try to change the text on the textView:
myTextView.text = #"Some string";
the app crashes with this error:
Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
Any suggestion is very appreciated.
Thanks
The error sounds like you are setting the text property from a code block that is not executing on the main thread. Check to make sure that any code you have that modifies UIKit objects does so while on the main thread. Example below:
dispatch_async(dispatch_get_main_queue(), ^{
// Set text here
myTextView.text = #"Some string";
});
Related
In my iOS5 application, I have UITableView that would display cells based on NSString values stored in progressLabelArray. I have registered a call back from my lower layers and I receive them in a C function from where I manage to call the UI update method through a reference to self.
static void callback_handler(int nCode) {
[refToSelf updateProgressView:nCode];
}
-(void) updateProgressView:(int32_t) nCode
{
NSString *status = nil;
status = [self progressUpdateToString:nCode];
[self.progressLabelArray insertObject:status atIndex:0];
[self.progressTableView reloadData];
[self.progressTableView setNeedsDisplay];
}
I guess, since the callbacks are coming on the same (UI thread), performSelectorOnMainThread may not be required.
My problem is that the table view only gets refreshed when the entire operation is complete, showing the last call back values. Is there a way by which I can force the UI to refresh after every callback? The callbacks coming might be relatively fast.
Resolved the issue by running the progress code in a separate thread. The callbacks come on a seprate thread and there I update my main thread (UI thread). I guess the UI thread was not getting any cycles to update the UI.
Put your
tableView.reloadData()
call in the following block and your tableview will refresh without any issue and without refreshing the scroller like in realtime apps.
For swift 3:
DispatchQueue.main.async()
{
tableView.reloadData()
}
For Objective C:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Background work
[tableView reloadData];
});
OK, so I have an app with a UITextView that I want to exhibit standard Undo behaviour. I have trawled lots of tutorials and answers on this site as well as the Apple Developer Docs and I can't understand why what I have produced is not working.
Whenever the UITextView is modified (I am using a non-standard keyboard using the textView.inputView property) the method below is passed a string that is the new text required for the text view:
- (void)setText:(NSString*)text{
NSString *oldText = [textView.text mutableCopy];
if (text != oldText) {
[undoManager registerUndoWithTarget:self selector:#selector(setText:) object:oldText];
textView.text = text;
}
}
and then to implement the undo when a UIButton is pressed
[undoManager undo];
is executed.
I have declared undoManager in my header file using
NSUndoManager *undoManager;
and synthesised it in my implementation but when I press the undo UIButton nothing happens and setText is never called. Where am I going wrong?
I think the initialisation of the undoManager is still missing in your example. You declare
NSUndoManager *undoManager;
in you headerfile, but I do not see where you allocate/initialize it.
Try adding
undoManger = [NSUndoManager alloc] init];
in you i.e. "viewDidLoad" (or similar) method. Do not forget to release the object appropriate, when you don't need it anymore, for example in dealloc.
I want to change an uiimage.image by calling a method in my viewcontroller:
-(void) aendereBild: (NSData*)bildngage {
UIImage *uiimageAusData = [UIImage imageWithData: bildngage];
drawImage.image = uiimageAusData;
}
To make it short: The image is not changing. This is not due to the NSData I pass (which i first thought was the problem). This method is called from the appdelegate.
In another void in this viewcontroller I can change the image with drawimage.image = otherimage without any problems, so I think the call from the AppDelegate is causing the problem. Anyone an idea what I did wrong? Thankie!
I think #tonclon has it right that the call from the appDelegate isn't happening in the right thread. An easy way to check is to put a breakpoint on the line that works and the line that doesn't and look at what thread is being used (shown in the Xcode debugger).
This question shows you how you do the update in the right thread if that's the case:
How do I update the UI in the middle of this thread?
You need something like
[drawImage performSelectorOnMainThread:#selector(setImage:) withObject:uiimageAusData waitUntilDone:NO];
The threads that make calls onto the appDelegate aren't necessarily the main thread -- you should check. Your app starts with a few threads, even if you didn't make any.
I'm messing around with the iphone sdk and with universal apps. I have UITextView in both my iphone class and a shared class I called Shared (In my Shared class the UITextVIew is called textInput).
I have a UIButton that when pressed, calls a method of the Shared class since I allocate an instance of the Shared class when app finishes launching and gets the value from the UITextView in the Shared class and sets the UITextVIew to that text. I would think that would work, however in my IBAction method for the button being pressed, I've tried it two different ways of:
[textInput setText:#"Accessing web service..."];
// textInput.text = #"Accessing web service...";
NSLog(#"self textInput: %s", [self textInput].text);
However, my NSLog shows null which I don't understand. But if I did something similar and in my UITextView of my iphone app delegate.m, if when the button is pressed, instead of calling the Shared method, I just said
textView.text = #"Hello"; // textView is the UITextVIew in my iphone class
it works. So I am having trouble seeing the disconnect. Any thoughts? Thanks.
Looks like it's just your NSLog call that's in error. NSLog uses %# as an output specifier for NSStrings.
NSLog(#"self textInput: %#", textInput.text);
I have a UITableView with the following code:
- (void)viewDidLoad {
[super viewDidLoad];
parser = [[XMLParser alloc] init];
[parser parseXML];
My problem is that the launch takes too long because it's parsing everything before displaying the view controller with the UITableView. Also, if I set up another UITableView and parse another XML (in a different tab) I tap to go the other tab, but then it hangs while it parses the other XML, and once it's done, then it display the UITableView.
I have looked for information on when to start the parsing, reload the UITableView and how to show a loading screen while the parsing code runs, but have not been able to come up with anything.
Anyone have any ideas?
You can call something like
[parser performSelectorInBackground:#selector(parseXML) withObject:nil];
on your main thread to run the parseXML code in a different thread. Just be careful to not update the ui from that thread. To update the UI from the parser thread, you'll need to call something like
[self performSelectorOnMainThread:#selector(XMLUpdated:) withObject:self waitUntilDone:NO];
If by loading screen you mean an activity indicator then trying to add the indicator animated before parsing could potentially not work because when you parse on the main thread it blocks and does not let the indicator appear on screen. To get around this i would do the parsing on a background thread, this should allow your indicator to appear, when the parsing is done, ahve the parsing object send a message to your viewController so i t knows its ready to show the tableview. (i should mention that UIKit is not thread safe and you should not try to update any UI elements from the background thread without using performSelectorInMainThread)