Cocoa: NSTimer gdb when invalidating - cocoa

I'm using some timers and want the user to be able to cancel it before it's done, or remove it from a view after it has finished. Both of these things are supposed to be handled by a cancelAction method. If the timer hasn't finished, an if statement in cancelAction tells the timers to invalidate, makes them nil and removes the view displaying the time left. This works perfectly. If the timers already finished, cancelAction only removes the view, and does not try to invalidate them. But this doesn't seem to work. If I cancel before they finish, everything works, If I cancel after they finished, it throws an exception saying unrecognized selector sent to instance. Both timer were made using the scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: method
The difference between calling before or after they finished, is that if they finished, this method is run.
- (void)timerFinished:(id)sender {
[timer invalidate];
timer = nil;
[timerLabelUpdater invalidate];
timerLabelUpdater = nil;
}
This is where it gets strange. If I just remove [timerLaberUpdater invalidate] the method gets called and it gets removed. I don't want to remove that line because that timer counts down the time left and updates the view with the time left. If I don't invalidate it, it keeps counting down to the negatives, plus it takes up memory.
I sincerely have no idea why removing that line changes anything, both timers were called in the same way, and if I remove the other line, it still doesn't work, ONLY by removing that instruction does anything change.
I get EXC BAD ACCESS in gdb, which I think means the selector is sent to an instance that was released.
Thanks for the help.

if([timerLabelUpdater isValid])
[timerLabelUpdater invalidate];

Related

GCDAsyncSocket didReadData only gets called once

I am trying to set up a Java server talking to a iPhone client using GCDAsyncSocket. For some reason my client code on the iPhone is not reading back all of the data.
I see didReadData gets called the first time, but never again. Ideally, I need to mimic the functionality of the HTTP protocol where it sends a header and then the payload. The size of the payload would be in the header. But that wasn't working, so I simplified my code even further in hopes of finding the issue. Below is the code, and below that the output.
client:
- (BOOL) sendString:(NSString *) string
{
[asyncSocket writeData:[string dataUsingEncoding:NSUTF8StringEncoding]
withTimeout:-1 tag:TAG_PAYLOAD];
[asyncSocket readDataToLength:1 withTimeout:(-1) tag:TAG_HEADER];
}
- (void) socket:(GCDAsyncSocket *) sock didReadData:(NSData *)data
withTag:(long)tag
{
NSString *str = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
NSLog(#"Read data %# with tag: %ld", str, tag);
if(tag == TAG_HEADER)
{
//TODO - parse the header, get the fields
[sock readDataToLength:3 withTimeout:-1 tag:TAG_PAYLOAD];
//[sock readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1
tag:TAG_PAYLOAD];
}
else
{
NSLog(#"Payload... %#", str);
NSLog(#"Tag: %ld", tag);
}
}
Java server:
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
String clientCommand = in.readLine();
System.out.println("Client Says :" + clientCommand);
out.println("Andrew\r\nAUSTIN\r\n");
out.flush();
However, on the client, the only thing I get back is A. The exact output is:
Read data A with tag: 10
My question is:
How come the didReadData method is never called again? There should be more of "Andrew\r\nAustin" recv'd back on the client. But it just hangs. The readDataToData and readDataToLength both seem to never get the full string.
I noticed the CRLF defined in GCDAsyncSocket.h is not \r\n but instead the hex values. Does this matter? Thats why I tried the readDataToLength method but that still failed. But I would like to know if this matters cross-platform or not.
Thanks.
OK - so I figured it out after pulling out what little hair I have left.
What is happening is that I have client code above in a separate class outside of the view. Practically all of the examples I came across had the GCDAsyncSocket stuff handled inside the view. It works great in there! I really didn't want to do this because on each view I need to send/read data and didn't want to duplicate my work. By placing an NSLog() line in the dealloc method of this helper class, called SocketComm, I was able to see it was getting deallocated before it was firing. So I needed to change the way I was calling my helper class. I declare SocketComm* sockComm a strong property in the viewController.h file and allocated it in the viewDidLoad() method. This means that it stays in scope the whole time. Of course, this means I need to deallocate it manually and do some other housekeeping things.
I still am not sure if this is the best way to handle this situation either, as far as memory management goes. Because now I will have to alloc this on every viewDidLoad method. It seems like it should be simpler than this, but here we are. And I still don't know why it never read the data the first time (my only guess is that the GCDAsyncSocket library or the iphone software detected a dead thread when the parent that spawned it got deallocated and decided to terminate it - but this is only a guess as I have just started objective-c).
This would also explain why sometimes it would work and sometimes it wouldn't. It seemed like it was in a race condition. Not sure if the above code I originally posted resulted in a race condition exactly, but some things I would try would work, and then the next time fail. It never read more than the first time though, and only about half the time would it even read that. Sometimes it wouldn't even send the data out over the socket!
In summation (and for whoever else comes looking for an answer):
Always check your memory management. I had to place an NSLog in dealloc() of the SocketComm helper class to fully see what was happening, and as soon as I did that I knew what the culprit was.
If you get weird results where sometimes it works and sometimes it doesn't, check your memory management. For me, sometimes it would do the first read and sometimes it wouldn't. This lead me to believe the thread was getting terminated.
If I find a better way to do this I will come back and update this answer.
Memory management. Let me repeat: memory management.

How to delete the dispatched block using GCD

I have this code:
_myQueue = dispatch_queue_create("com.myapp", DISPATCH_QUEUE_SERIAL);
_mainQueue = dispatch_get_main_queue();
and lot of this block that require some seconds (or minutes)
dispatch_async(_myQueue,
^{
if(canRun){
dispatch_async(_mainQueue,^{/* updating interface here */});
// code here
}
});
My app have a "Stop" button to try stopping all job, and the BOOL "canRun" help me to execute all blocks w/o do nothing.....but always I have to wait the completition of each block until the queue come 0.
Is there any way to instantly "clean" the queue istead doing that?
The aim is to stop processes and to start over without closing and reopening the application.
This project works under ARC.
You can cancel them if you take a few extra steps to creat a dispatch_source object and keep a reference to it.
Review this for starters
https://developer.apple.com/library/mac/documentation/Performance/Reference/GCD_libdispatch_Ref/index.html
There are functions to pause, resume and cancel.

A way to schedule a method call in Cocoa?

I'd like to call a method
-(void) fooWithObject:(MyObject *)obj;
On a given time (NSDate instance)
without blocking the main thread.
What is the best way to go about this? I've seen NSTimer, performSelector and NSOperation but reading a bit of each just made me more confused.
Important:
Ability to pass in an object to the method I'm calling
A way to set time of execution
Non blocking
Don't need repeats
Cheers!
performSelector:withObject:afterDelay can be used for this. The delay is relative so you need to compute the difference between your desired date and the current time. Something like this (typed directly into answer on an iPad - E&OE):
- (void) fooWithObject:(MyObject *)obj onDate:(NSDate *)onDate
{
[self performSelector:#selector(fooWithObject:)
withObject:obj
afterDelay:MAX(0, [onDate timeIntervalSinceNow])
];
}
Note that MAX is used in case the passed in date is in the past - the delay will be 0 and the selector will therefore be performed "as soon as possible".

What is considered overloading the main thread?

I am displaying information from a data model on a user interface. My current approach to doing so is by means of delegation as follows:
#protocol DataModelDelegate <NSObject>
- (void)updateUIFromDataModel;
#end
I am implementing the delegate method in my controller class as follows, using GCD to push the UI updating to the main thread:
- (void)updateUIFromDataModel {
dispatch_async(dispatch_get_main_queue(), ^{
// Code to update various UI controllers
// ...
// ...
});
}
What I am concerned about is that in some situations, this method can be called very frequently (~1000 times per second, each updating multiple UI objects), which to me feels very much like I am 'spamming' the main thread with commands.
Is this too much to be sending to the main thread? If so does anyone have any ideas on what would be the best way of approaching this?
I have looked into dispatch_apply, but that appears to be more useful when coalescing data, which is not what I am after - I really just want to skip updates if they are too frequent so only a sane amount of updates are sent to the main thread!
I was considering taking a different approach and implementing a timer instead to constantly poll the data, say every 10 ms, however since the data updating tends to be sporadic I feel that it would be wasteful to do so.
Combining both approaches, another option I have considered would be to wait for an update message and respond by setting the timer to poll the data at a set interval, and then disabling the timer if the data appears to have stopped changing. But would this be over-complicating the issue, and would the sane approach be to simply have a constant timer running?
edit: Added an answer below showing the adaptations using a dispatch source
One option is to use a Dispatch Source with type DISPATCH_SOURCE_TYPE_DATA_OR which lets you post events repeatedly and have libdispatch combine them together for you. When you have something to post, you use dispatch_source_merge_data to let it know there's something new to do. Multiple calls to dispatch_source_merge_data will be coalesced together if the target queue (in your case, the main queue) is busy.
I have been experimenting with dispatch sources and got it working as expected now - Here is how I have adapted my class implementation in case it is of use to anyone who comes across this question:
#implementation AppController {
#private
dispatch_source_t _gcdUpdateUI;
}
- (void)awakeFromNib {
// Added the following code to set up the dispatch source event handler:
_gcdUpdateUI = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0,
dispatch_get_main_queue());
dispatch_source_set_event_handler(_gcdUpdateUI, ^{
// For each UI element I want to update, pull data from model object:
// For testing purposes - print out a notification:
printf("Data Received. Messages Passed: %ld\n",
dispatch_source_get_data(_gcdUpdateUI));
});
dispatch_resume(_gcdUpdateUI);
}
And now in the delegate method I have removed the call to dispatch_async, and replaced it with the following:
- (void)updateUIFromDataModel {
dispatch_source_merge_data(_gcdUpdateUI, 1);
}
This is working absolutely fine for me. Now Even during the most intense data updating the UI stays perfectly responsive.
Although the printf() output was a very crude way of checking if the coalescing is working, a quick scrolling back up the console output showed me that the majority of the messages print outs had a value 1 (easily 98% of them), however there were the intermittent jumps to around 10-20, reaching a peak value of just over 100 coalesced messages around a time when the model was sending the most update messages.
Thanks again for the help!
If the app beach-balls under heavy load, then you've blocked the main thread for too long and you need to implement a coalescing strategy for UI updates. If the app remains responsive to clicks, and doesn't beach-ball, then you're fine.

Updating UI in Cocoa from another .m file

I have a GUI app that has a main thread and then I use NSOperation to run 2 other threads once the user clicks the Start button. Now one thread calculates a certain value and updates it. What I want thread 2 to do is to pick this value up and update the UI.
How do I get a IBOutlet Textfield value to get updated on the UI from this second thread ?
eg:
main.m --- handles the UI and has code to start the 2 threads when the user hits the Start Button.
thread1.m -- calculates a particular value and keeps doing it until the user hits stop.
thread2.m - Need to use this thread to update the UI in main.m with the the value that thread1.m calculates.
I am unable to accomplish the thread2.m task and update the UI. My issue is that how do I define a IBOutlet and update it with a value from thread2/1 so that the main.m has access to this value and updates the UI. I have access to the actual variable in main.m and can print it out using NSLog. Its just that I am getting stuck on how to update the UI with this value. As I need to have theIBOutlet in main.m to tie it with the UILabel in the app. Any ideas guys ? Thanks.
Could you add pointers to your thread1.m and thread2.m files? Then set them with either a constructor method or some accessor methods?
If I understand the situation you described in your example, and assuming what you are calculating is an int (you can modify as you need):
Add an accessor to thread1.m
-(int)showCurrentCalcValue
{
//Assume that you get calculatedValue from whereever else in your thread.
return calculatedValue;
}
Then add to thread2.m
NSTextField *guiTextField;
Thread1 *thread1;
-(void) setThread: (Thread1 *aThread)
{
self.thread1 = aThread;
}
-(void) setGuiTextField: (NSTextField *aTextField)
{
self.guiTextField = aTextField;
}
-(void) updateGUI()
{
[guiTextField setStringValue: [thread1 showCurrentCalcValue]];
}
Presuming your main.m is something like the following:
IBOutlet NSTextField *outputDisplay
-(void) setUpThreads()
{
Thread1 *thread1 = [[Thread1 alloc] init];
Thread2 *thread2 = [[Thread2 alloc] init];
[thread2 setGuiTextField: outputDisplay];
[thread2 setThread: thread1];
//Whatever else you need to do
}
Then just take care of setting everything and calling the methods in your threads.
Source code files don't matter. You could have all of this stuff in one file (not that that would be a good idea) and the problem would be unchanged. What matters are the classes.
Classes are not simply bags of code; you design them, you name them, and you define each class's area of responsibility. A class and/or instances of it do certain things; you define what those things are and aren't.
When writing NSOperation subclasses, don't worry about the threads. There's no guarantee they even will run on separate threads. Each operation is simply a unit of work; you write an operation to do one thing, whatever that may be.
eg: main.m --- handles the UI and has code to start the 2 threads —
operations
— when the user hits the Start Button.
thread1.m -- calculates a particular value and keeps doing it until the user hits stop.
That's not one thing; that's an indefinite sequence of things.
thread2.m - Need to use this thread to update the UI in main.m with the the value that thread1.m calculates.
You should not touch the UI from (what may be) a secondary thread. See the Threading Programming Guide, especially the Thread Safety Summary.
I don't see why this should even be threaded at all. You can do all of this much more easily with an NSTimer running on the main thread.
If it would be inappropriate to “calculate… a particular value” on the main thread, you could make that an operation. Your response to the timer message will create an operation and add it to your computation queue. When the user hits stop, that action will go through on the main thread; invalidate the timer and wait for the queue to finish all of its remaining operations.
With either solution, “thread2.m” goes away entirely. Your update(s) to the UI will (and must) happen entirely on the main thread. With the latter solution, you don't even have to wait until you're done; you can update the UI with current progress information every time you receive the timer message.

Resources