iphone - asynchronous upload and download operation freezes the UI - iphone

In my app , I want to achieve multiple uploads and downloads using Websocket protocol.
For that purpose , I have made class called Engine , Upload and Download
Engine - creates a operationQueue and maximumConcurrentOperation is 3 .
Upload and Download - subclass of NSOperation and override the main method . In main method , both the class have following statements
Engine.m
-(id)init
{
if(self = [super init])
{
opQueue = [[NSOperationQueue alloc] init];
opQueue.maximumConcurrentOperationCount = 3 ;
}
}
-(void)startUploadWithPath:(NSString *)file
{
Upload *up = [[Upload alloc] initWithPath:file];
[opQueue addOperation:up];
}
-(void)startDownloadWithPath:(NSString *)file
{
Download *down = [[Upload alloc] initWithPath:file];
[opQueue addOperation:down];
}
Upload.m and Download.m
-(void)main
{
//start transfering data to server
while(workCompleted != YES)
{
// wait()
}
// when work completed
//insertIntoDB();
}
Problem : When I try to upload first video , then it works fine . Immidiately if I try to upload second video , then also it works fine . When I try to upload third video(i.e when I select video from gallery and video compression has not began yet) , the application freeze . The application becomes active only when one of the two previous video upload is completed .
Why does the application freeze even if maxConcurrentOperationCount is 3 ?
Thanks in advance.

try uploading videos in parallel, for example like this:
[NSThread detachNewThreadSelector:#selector(inParallel) toTarget:self withObject:nil];
...
-(void)inParallel {
NSLog(#"occurs in parallel");
}
this should not freeze the UI but it is worth trying

Related

iphone-bitly question

I am using https://github.com/st3fan/iphone-bitly classes and as the example i want to do something for which i want your help.
- (void) demo
{
URLShortener* shortener = [[URLShortener new] autorelease];
if (shortener != nil) {
shortener.delegate = self;
shortener.login = #"LOGIN-REPLACE-ME";
shortener.key = #"KEY-REPLACE-ME";
shortener.url = [NSURL URLWithString: #"http://stefan.arentz.ca"];
[shortener execute];
///// I want to get result on here not in the delegate for further usage in my function
}
}
any help or suggestion
What you're requesting would block the current thread. If you ran that on the main thread, you'd hang your app. The framework you've linked only provides an asynchronous interface for that reason.
If you're already running this on a background thread, you can re-implement execute to use [NSURLConnection sendSynchronousRequest:returningResponse:error:]. But never run that on your main thread.

iPhone: Streaming music while application is in background

I have an app that streams music using AudioStreamer class by Matt Gallagher. This works fine as a background process except I want to be able to skip to the next song once the stream is finished. Unfortunately this part doesn't work.
Initially I had a timer that was monitoring the stream but realized that when the app backgrounds this timer no longer runs. So I tried adding a delegate callback in the packet read function:
void ASReadStreamCallBack(CFReadStreamRef aStream, CFStreamEventType eventType, void* inClientInfo)
{
AudioStreamer* streamer = (AudioStreamer *)inClientInfo;
double percent = [streamer progress]/[streamer duration];
if(percent>=0.98 || (percent>=0.95 && [streamer isIdle])){
if([streamer.delegate respondsToSelector:#selector(didFinishPlayingStream:)] ){
[streamer.delegate didFinishPlayingStream:streamer];
streamer.delegate = nil;
}
}
[streamer handleReadFromStream:aStream eventType:eventType];
}
This works fine when the app is in the foreground but no longer works when the app is backgrounding. The delegate method basically sends a request to get the stream URL for the next song, then once it has it creates a new AudioStreamer class
While the app is in background you can implemente the delegate to handle the different remote control states.
- (void)remoteControlReceivedWithEvent:(UIEvent *)receivedEvent {
switch (receivedEvent.subtype) {
case UIEventSubtypeRemoteControlTogglePlayPause:
if (player.isPlaying) {
[player pause];
} else {
[player start];
}
break;
case UIEventSubtypeRemoteControlPreviousTrack:
break;
case UIEventSubtypeRemoteControlNextTrack:
[self skipSong:nil];
break;
default:
break;
} }
Something like this works for me.
I've uploaded my AudioPlayer/streamer class inspired in part by Matt Gallagher's AudioStreamer to
https://code.google.com/p/audjustable.
One of the cooler features is its support for gapless playback. This means the AudioQueue is never closed between gaps; keeping iOS from suspending your app.
You can implement AudioPlayerDelegate:didFinishBufferingSourceWithQueueItemId and AudioPlayerDelegate:didFinishPlayingQueueItemId to queue up the next track by calling AudioPlayer:queueDataSource.
Let me know if you need help using it.

Grabbing the UIPasteboard like Pastebot while running in the background

I know this is possible as Tapbots Pastebot does this. I am trying to grab the UIPasteboard when my iPhone app is running in the background and add it to a UITableView just as Pastebot does but I am also trying to shorten the link, if its a URL and copy that back to the UIPastboard so its ready for the user to paste anywhere. Now Pastebot apparently runs in the background by playing an audio file for 10 minutes. I have set up the NSNotificationCenter like so in the applicationDidFinishLaunching
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(pasteboardChangedNotification:) name:UIPasteboardChangedNotification object:[UIPasteboard generalPasteboard]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(pasteboardChangedNotification:) name:UIPasteboardRemovedNotification object:[UIPasteboard generalPasteboard]];
- (void)pasteboardChangedNotification:(NSNotification*)notification {
pasteboardChangeCount_ = [UIPasteboard generalPasteboard].changeCount;
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
if (pasteboardChangeCount_ != [UIPasteboard generalPasteboard].changeCount) {
[[NSNotificationCenter defaultCenter] postNotificationName:UIPasteboardChangedNotification object:[UIPasteboard generalPasteboard]];
}
}
Can anyone point me in a direction on grabbing the UIPasteboard and shortening a link, if its a URL and sending it back to the UIPasteboard? I have read the multitasking dev documents and the UIPasteboard documents. If anyone has a solution can you please share them with me?
Thanks
The only way I have managed to achieve something similar is by not bothering with the NSNotificationCenter and instead just copying the contents of the UIPasteboard at regular intervals whilst in the background.
The code bellow checks the UIPasteboard once a second for a thousand seconds. I believe that an application can run in the background for around 10 minutes without playing audio. If you play an audio file in the background the application can keep running.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Create a background task identifier
__block UIBackgroundTaskIdentifier task;
task = [application beginBackgroundTaskWithExpirationHandler:^{
NSLog(#"System terminated background task early");
[application endBackgroundTask:task];
}];
// If the system refuses to allow the task return
if (task == UIBackgroundTaskInvalid)
{
NSLog(#"System refuses to allow background task");
return;
}
// Do the task
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSString *pastboardContents = nil;
for (int i = 0; i < 1000; i++)
{
if (![pastboardContents isEqualToString:[UIPasteboard generalPasteboard].string])
{
pastboardContents = [UIPasteboard generalPasteboard].string;
NSLog(#"Pasteboard Contents: %#", pastboardContents);
}
// Wait some time before going to the beginning of the loop
[NSThread sleepForTimeInterval:1];
}
// End the task
[application endBackgroundTask:task];
});
}
Tapbots actually wrote an entry on their blog a few months back about the trick they use to get at the clipboard in the background. I don't use the app myself, so I can't verify that this ever came to fruition, but here's the relevant blog entry.
I know this is kind of an old thread. But I'd like to share this with you:
http://blog.daanraman.com/coding/monitor-the-ios-pasteboard-while-running-in-the-background/#comment-15135
However, I have my doubts whether Apple will reject this when trying to submit it to the App Store, as it feels to me like a hack. A hack that Apple tries hard to avoid with its whole background multitasking thing.
Anyone thoughts about it?

Sound playback delay (hiccup) when OpenAL is implemented on iphone

I implemented OpenAL code to my iphone game. When I starts the game, it runs for 1 sec and stalls for 2 sec then resumes (hiccup effect). I believe its delayed due to the sound files loading. What is the solution? Can anyone recommend any book, site or sources code (not the iphone reference, please)? Is there a loading process and where should I initialize the loading process? Would that help?
Below, I have included the related components of the OpenAL code that I have implemented. The sound file will be played and invoked by a "if" statement in the gameloop. The OpenALController class is for the sound sources and buffers creation and the InitOpenAL method is invoked in OpenALController. MyView is a customized subclass of UIView and connected to the main view (I didn't use the default view).
// MyView.m
// A customized UIView as the main view.
#import "OpenALSoundController.h"
- (void)startPlaying{
...
[self initializeValuables];
...
[self initializeTimer];
}
- (void)initializeTimer {
if (theTimer == nil) {
theTimer = [CADisplayLink displayLinkWithTarget:self selector:#selector)gameLoop)];
theTimer.frameInterval = 2;
[theTimer addToRunLoop: [NSRunLoop currentRunLoop] forMode: NSDefaultRunLoopMode];
}
}
- (void)gameLoop {
...
If something = true
// Play the sound
[[OpenALSoundController sharedSoundController] playSound1];
...
}
...
#end
// OpenALSoundController.h
#interface OpenALSoundController : NSObject {
...}
...
+ (OpenALSoundController*) sharedSoundController
...
#end
// OpenALSoundController.m
// Singleton accessor
{
static OpenALSoundController* shared_sound_controller;
#synchronized(self)
{
if(nil == shared_sound_controller)
{
shared_sound_controller = [[OpenALSoundController alloc] init];
}
return shared_sound_controller;
}
return shared_sound_controller;
}
- (void) initOpenAL{
...
file_url = [[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:#"fire" ofType:#"wav"]];
firePcmData = MyGetOpenALAudioDataAll((CFURLRef)file_url, &data_size, &al_format,&sample_rate);
alBufferData(fireOutputBuffer, al_format, firePcmData, data_size, sample_rate);
[file_url release];
...
alSourcei(outputSourceFire, AL_BUFFER, fireOutputBuffer);
...
}
You might be interested in Finch, an OpenAL sound engine for iOS. It’s very well suited to games. It’s usually better to reuse some already existing code than develop and maintain your own.
First its better to use mp3, as wav files are huge and loading from disk takes time. Mp3 files are smaller on disk, loaded into memory and decompressed there for playing. Try experimenting by reducing mp3 bitrate/encoding quality too.
Also you need to preload sounds to avoid hiccups, otherwise you will have a delay the first time a sound is played.

How can I SIMPLY perform two tasks at once in my iPhone app? (threading?)

The Situation:
Somewhere in my app I start downloading data from my server. Before downloading starts, I would like to update a UILabel to say #"Now Downloading...". And set it back to blank when downloading is over.
The Problem: It seems like the download takes up all of the computers attention, and the UILabel never gets updated until the very end (at which downloading is already over) and so is set back to blank (or, never-visible in real time).
Question:
How can I SIMPLY update my UILabel to say "Now Downloading" just before the download?
label.text = #"Downloading";
NSOperationQueue *operationQueue = [[NSOperationQueue]alloc]init];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:#selector(download) object:#"http://www.google.com"];
[operationQueue addOperation:operation];
[operation release];
- (void)download:(NSString *)url
{
// do the download
[self performSelectorOnMainThread:#selector(didFinishDownload) withObject:nil waitUntilDone:NO];
}
- (void)didFinishDownload
{
label.text = #"";
}
If you use NSURLRequest -> NSURLConnection and the NSURLConnection's delegate methods this will perform the download in the background and will notify the delegate of incoming data. This will also allow you to display a progress.