iPhone Development:
I want to have an infinite loop constantly checking an NSMutableArray and if [size > 0] pull the first object, do something with it, remove it, wait .25 seconds, then continue checking.
I want my GUI buttons to add this list. Is there a way to do this? Is there a way to do this by having the loop in the main thread?
UPDATE
I guess i didn't ask the question properly. I'm using the AsyncSocket class to send telnet commands. I need to send them fast because their used to control a RC car, however the RC receiver is a tad slow. So i want to slow downs the rate in which my iPhone sends out the commands. Right now i have button events sending out the commands but i want to instead have the events add the command to a list/queue/array. In parralel to the button clicks I want a process to check the queue every .25 seconds and send out the commands in the queue.
MY PROBLEM:
the AsyncSocket isn't thread safe so I cannot have another thread sending commands. The documentation reads
If you find yourself on a thread which
is different from the thread on which
AsyncSocket is running, and you need
to invoke a method on AsyncSocket,
then you must use a method like
performSelector:onThread: to ensure
the method is invoked on AsyncSocket's
thread (and thereby maintaining
thread-safety)."
I dont know what this means...
What does this quote above mean?
Is multithreading required for what i want to do?
I would recommend looking into Key Value Observing. This will allow you to set up an observing class to be notified when entries are made into the array.
It'll be a bit harder than the standard tutorials you'll find, most simply observe a property being updated. You'll need to use -willChange:valuesAtIndexes:forKey: and -didChange:valuesAtIndexes:forKey: when you add elements to the array. If all you need to listen for is items added, this should be enough. However, you can look into ObservingOptions to really get finer control.
See more about NSKeyValueObserving here: http://developer.apple.com/library/ios/#documentation/cocoa/Reference/Foundation/Protocols/NSKeyValueObserving_Protocol/Reference/Reference.html#//apple_ref/occ/cat/NSKeyValueObserving
This method will allow you to not waste any cycles polling for changes.
This is easily solved by using an NSOperationsQueue.
add an NSTimer with interval 0.25 that will be cheking it in a loop.
Check documentation. There are some useful sample-projects
Related
I am working on a chat client. To get new messages (or post new one) I have to perform GET (or POST) request. All new messages are stored via core data. At the moment I don't know how to implement it in most optimal way.
My thoughts:
On view controller init stage create background thread which will periodically checks for new messages (if conversation is active - with short period, if not - with period about 60 secs). If there are new messages, we store them in DB and signal delegate that there are new messages to display.
Friend suggested to use performSelector afterDelay, but I don't understand how to use it in my app.
Something else?
Thanks in advance.
Don't use performSelector afterDelay. Using NSTimer is much better (as the trigger for starting the next download). Also, use NSOperationQueue to manage your background tasks. Create yourself a custom NSOperation that you can instantiate and it will complete your request process. When you create a new operation to check for new messages, check if one is already in progress (there is no point having multiple requests in progress at the same time).
Other notes:
Make sure you consider the threading with regards to the Core Data store (having the operation call back to the main thread with the results will probably be easiest as the result data will always be relatively small).
If you have lots of messages being sent and you want to show constant status (like Skype does, showing you when someone is typing) you would need to use sockets to keep the connection alive the whole time (the cost of new connections each time would be prohibitive).
I am trying to determine the best strategy to poll a webservice once a minute, parse the xml returned and then update an object stored in a shared instance. This process needs to run in a separate thread, and will continue as long as the app is running.
It seems that I could put all the code to call the webservice and parse the xml into an NSOperation and add that NSOperation to an NSOperationQueue stored in the app delegate as soon as the app launches.
Is it a correct approach to use an NSTimer inside the main method of the NSOperation so that the operation will loop once a minute, indefinitely? In that scenario the NSOperation would never actually return - this seems what I want but I am not sure if this is the right way to think about it.
The problem I am trying to solve is of course extremely common, so I am trying to figure out the correct way to implement it. Any advice greatly appreciated.
The real correct way to do it is to use push notifications. If any of your users have cell plans with limited data or data charged based on usage, they will thank you for it.
But if you insist on polling, you may as well use the NSTimer directly rather than messing with a timer inside an NSOperation. This will run on the main thread, but you could have the timer callback use performSelectorInBackground:withObject: to do processing in the background. Or you could just skip the timer altogether and run the whole polling sequence on a separate NSThread, and use sleepForTimeInterval: to delay between polls.
I would highly recommend you take a look at ASIHTTPRequest. What an amazing little class, and really well documented.
Edit:
Take a look at this answer for what seems to be the optimal solution.
one approach: create a thread and use a run loop, updating or idling as appropriate. then you can perform the request from the secondary thread and post it to the rest of the app after it's been parsed/prepped.
this way offers more control over pause/resume/delays/timing, and you can easily control the number of active requests (which should be exactly zero or one).
I wouldn't use NSTimer for this problem/design. I would create NSThread from the AppDelegate when the application starts. I would lower the priority of this thread. Inside the NSThread main method is basically a loop.
-(void)main {
while(true) {
// get raw data from url
// hash the result
// compare the hash to the last time
if (currentHash != lastHash) {
// post a notification to default center with the new data
lastHash = currentHash;
}
// sleep the thread sleepForTimeInterval
}
}
Your Model object would subscribe to the notification from the thread and parse the new data and updates ivars. Your View object would listen to the Model using KVO and display any updates/changes.
First of all, I am a a very new Objective C/Cocoa iOS Developer but I've written C/C++ applications before.
So I managed to run the Rabbitmq-c (http://hg.rabbitmq.com/rabbitmq-c/) client inside my iPhone App, and I can connect to Rabbitmq directly from my app and even consume a queue item. So all's good.
Now my problem is, my iPhone app needs to use the rabbitmq-c library to poll for incoming messages in from the server. Probably there will be, an almost infinite while loop.
Do I have to take this to a new thread? Ideally, I want to wrap the rabbitmq-c class as an Async objective C class and use NSNotification (or something similar) to notify my UI. I'm a bit leery of creating a new thread, as I read about stuffs like Runloop etc can solve a lot of problems without using an extra thread.
What is the best way for me to go about this? Any examples of code or directions would be helpful. Please remember, I am not dealing with an Objective C code/Coca rabbitmq library here, I'm using C code inside my iPhone app.
Thanks
Subrat
don't block the main thread with your server polling.
since the operation never ends, create your own thread and run loop for this server polling. you can potentially use the run loop (each thread has one) instead of the infinite while. the alternatives involve regularly spawning threads. it's easiest to just use one thread for this.
once you have an update, post the notification (if you choose NSNotification) from the main thread -- UIKit is meant to operate from the main thread only.
for samples, i'd begin with samples related to NSRunLoop and CFRunLoop.
good luck
You can also create custom delegates for updating the UI, or the stuff related to UIKit.
Notifications might be a little easier to code and offer the advantage that multiple objects can observe one notification. With delegates, such a thing cannot be done without modifying the delegating object (and is unusual).
Some advantages of delegating:
The connection between delegating object and delegate is made clearer, especially if implementing the delegate is mandatory.
If more than one type of message has to be passed from delegatee to delegate, delegating can make this clearer by specifying one delegate method per message.
Or other way is to write method to receive messages. This method can have infinite loop.
Later you can put this method in background thread like this.
[self performSelectorInBackground:#selector(receiveMessages) withObject:nil];
Let's say that if I read from www.example.com/number, I get a random number. In my iPhone app, I want to be able to continuously read from that address and display the new number on the screen after each request is finished. Let's also assume that I want this process to start as soon as the view loads. Lastly, as a side-note, I'm using ASIHTTPRequest to simplify the web requests.
Approach 1: In my viewDidLoad method I could synchronously read from the URL in a loop (execution will not continue until I get a response from the HTTP request). Pros: the requests are serial and I have full control to respond to each one. Cons: the UI never gets updated because I never exit the function and give control back to the run time loop. Clearly, this is not a good solution.
Approach 2: In my viewDidLoad method I create a timer which calls a fetchURL function once per second. Pros: each request is in a separate thread, and the UI updates after each request is finished. Cons: the requests are in separate threads, and cannot be controlled well. For example, if there is a connection timeout on the first request, I want to be able to display an error popup, and not have any further requests happen until settings are changed. However, with this approach, if it takes 3 seconds to timeout, two additional requests will have already been started in that time. If I just slow down the timer, then data comes in too slowly when the connection is working well.
It seems like there should be some approach which would merge the benefits of the first two approaches I mentioned. I would like a way that I could decide whether on not to send the next request based on the result of the previous request.
Approach 3: I considered using a timer which fires more quickly (say every .25 seconds), but have the timer's function check a flag to see what to do next. So, if the previous request has finished, it sends a new request (unless there was an error). Otherwise, if the previous request has not finished, the timer's function returns without sending a new request. By firing this timer more quickly, you would get better response time, but the flag would let me get the synchronization I wanted.
It seems like Approach 3 would do what I want, but it also seems a little forced. Does anyone have a suggestion for a better approach to this, or is something like Approach 3 the best way to do it?
You could do this using GCD with less code and using fewer resources. This is how you could do it:
In viewDidLoad call a block asynchronously (using dispatch_async) that does the following:
Load the data with a synchronous call and handle timeouts if it failed.
If successful, inform the main thread to update the UI.
Queue a new block to run after a delay that does the same thing (using dispatch_after).
To call back to the main thread from another thread I can think of these methods:
If you want to update a custom view, you can set setNeedsDisplay from your block
Otherwise, you could queue a block on what's called "main queue", which is a queue running on the main thread. You get this queue by calling dispatch_get_main_queue. and then treat it like any other queue (for example you can add your block by calling dispatch_async).
If you don't want to use blocks you can use the NSObject's performSelectorOnMainThread:withObject:waitUntilDone: method.
See GCD Reference for more details.
That said, you should never keep performing small requests so frequently (unless for specific tasks like fetching game data or something). It will severely reduce battery life by keeping antenna from sleeping.
I believe an NSOperation is what you need. Use the number 1 solution above, but place the code in your NSOperation's main method. Something like this:
The .h file
#interface MyRandomNumberFetcher : NSOperation {
}
#end
The .m file
#implementation MyRandomNumberFetcher
- (void) main {
// This is where you start the web service calls.
}
#end
I'd also recommend adding a reference to the UI controller so your operation queue class can call it back when it's appropriate.
Here's another suggestion. Create an NSOperationQueue that will run your requests on a different thread. If you find you need to refresh the UI call performSelectorOnMainThread. When the request completes create another request and add it to the queue. Set the queue to run only one action at a time.
This way you'll never have two requests running at the same time.
I have some slow internet task to save and load file, I'd like to do those slow tasks in some background thread. I am wondering whether that's doable, and if it is, any sample code?
Then after it is finished, I'd like it to notice back to the main thread, so that I could update the UI.
Take a look at NSURLConnection. It will load an NSURL (using NSURLRequest) in the background, and send delegate methods regarding its status.
Ultimately the device you are running your code on has a single processor and cannot possibly load large quantities (gigabytes) of data. The best route, by is likely that suggested by Ben (NSURLConnection asynchronously) which gives you the added advantage of being able to cleanly cancel and handle error messages. While it isn't technically threaded in the way you probably think you want it to be, it is well integrated with the event loop and is non-blocking. If that is still not enough, I would suggest looking at NSOperation and NSOperationQueue. You can fire off an NSOperation sub-class object and perform the download there (I would still advise doing it asynchronously there so as to enable canceling, pausing, etc).
Log in to the iPhone Developer Center and search for Introduction to Threading Programming. Or, maybe you can log in and use this link:
http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/Multithreading/Introduction/chapter_1_section_1.html#//apple_ref/doc/uid/10000057i-CH1-SW1
If you do decide you need a background thread even after using asynchronous HTTP calls to gather the data, don't forget to wrap the background thread code in a new NSAutoReelasePool and then release it at the end.