What's the difference between AVPlayer and AVAudioPlayer in terms of functionality? - ios

I've been trying to use AVAudioPlayer to play remote MP3 files in my app and I've read some of the other answers on Stack Overflow but I still cannot get it to work. The common suggestion I'm reading is to use AVPlayer instead of AVAudioPlayer. I don't know why this is. Also, in one of the questions the accepted answer mentioned that one needs to create an instance of AVPlayer in order to use it in the app. What should I do?

What you've read is correct. Creating an instance of AVPlayer will allow you to successfully run your code.
You should initialize your AVPlayer outside of where you want to call it.
var myPlayer = AVPlayer()
Now, in a separate place in your code, try something like this:
func playAudio() {
//initialize whatever you have to (you seem to have that correct)
//now call myPlayer.play(), and that should work correctly
}
Let me know if this helps.

Related

Can I use replaceCurrentItemWithPlayerItem with AVQueuePlayer?

I have used replaceCurrentItemWithPlayerItem: with AVPlayer but can it be also used with AVQueuePlayer?
In following apple doc, it is given that:
This method must only be invoked on player instances created without
queues. If the player is initialized with multiple items the method
throws an exception.
What does it means? Please guide.
If it signifies that it throws exception if we use it with AVQueuePlayer, then I tried using it without any exception but dont know if it is right way to use.
https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVPlayer_Class/
No you can't, as per Apple docs:
Important
This method is not intended for use with AVQueuePlayer. If the player is initialized with multiple items this method throws an exception.
Here's the link: https://developer.apple.com/reference/avfoundation/avplayer/1390806-replacecurrentitemwithplayeritem?language=objc

Pass a variable from foreground to background in Swift

I am developing an iOS application where I want to record the time when a user presses a particular button and keep it. Later I will use this time record in background. Is there a nice way of doing that without invoking NSUserDefaults or CoreData or whatever other database?
I am very new to iOS development. I think this is very likely to be a naive question. But I'm just curious. Please don't laugh at me haha.
Edit: This is indeed a very naive question haha.
A simple way to make sure your data is available everywhere in your app and only persists for each app session would be to use a singleton. Something like this.
// Create a class to store the data
class SessionData : NSObject {
// Create a shared instance of your class
static let sharedInstance = SessionData()
// Create a variable to store the date object
var timeStore:NSDate?
}
This will mean that anywhere in your app you can get and set this data as below.
// Get
if let time = SessionData.sharedInstance.timeStore {
println(time)
}
// Set
SessionData.sharedInstance.timeStore = NSDate()
It is worth mentioning that despite the above being a valid method, You may be able to avoid doing this by re-thinking your app structure and passing data between classes instead. You should have a look at Delegation.
Also as #CouchDeveloper mentions in their comment below, you may want to included a dispatch queue to prevent crashes or locks in the situation where two or more classes try to read and or write data at the same time.

Setting NSOutputStream to be synchronous

I know there are few questions similar to this one, but in all cases the answer is to make it asynchronous.
According to the apple documentation (even though it is not recommended) polling is an available option. However, I just couldn't implement it.
Should probably mention I am doing it in c# using Xamarin, but if you
can give me an answer on how to do this in Objective-C that would be
good too.
Here is my attempt
while(true)
{
if (outStream.HasSpaceAvailable())
{
int output = ((NSOutputStream)outStream).Write(data, (uint)data.Count());
}
}
The problem here is that outStream.HasSpaceAvailable() is false indefinitely.
Reason why I want to do it synchronously:
Currently (in a test app) I am doing it asynchronously and it works for sending one stream of data per call to the method. However in the real App I will need to send lots of small data packets one after the other. Therefore, I need to wait for the data to be sent before I can send another packet.
If I try putting many calls to the delegate the data keeps overwriting the previous call...
It would be great if you could let me know how to do it synchronously first (for the sake of having one answer out there on it). If you think there is a better way to do it in an async way let me know too.
Thanks
EDIT :
Here is how I set up the session
SESSION=new EASession (Accessory, Protocol);
NSStreamStatus outputStream= SESSION.OutputSream;
outputStream.Open();
This is done when a button is pressed and before the while loop above (obviously).

Organize multiple NSURLSessionTasks

I have an iOS app that can download files from a website. I have created a NSURLSession in a class Downloads to manage them. The Downloads class has a NSMutableArray that keeps track of all current and past downloads using my DownloadItem objects. I am not happy with this setup.
Currently, I have to have the Downloads class as the delegate for all downloads. I see no way to assign the delegate of each NSURLSessionDownloadTask to a DownloadItem object. So, I have to keep it assigned to my Downloads object and then have it figure out which way DownloadItem to forward the message on to.
Currently I do this by making an NSMutableDictionary called tasksDictionary in the Downloads and use the taskIdentifier as a key.
return [self.tasksDictionary objectForKey:[NSNumber numberWithInteger:task.taskIdentifier]];
This seems to work, but it doesn't seem the most efficient method. I'm also concerned that I saw the first taskIdentifier created was 0 which will make it difficult to discern the difference between a completed task and the first task.
Is there a better way to keep track of these things? Is there a way to assign a new delegate for a task?
Perhaps have these ivars:
NSMutableArray *completedDownloads;
NSMutableDictionary *activeDownloadTasks; // #(taskID) => DownloadItem
When you finish, pop the DownloadItem from activeDownloadTasks and add it to completedDownloads.
Otherwise what you are doing sounds peachy.
While I'm at it, this syntax may be helpful (using your example):
return self.tasksDictionary[#(task.taskIdentifier)];

iOS: Moving instance of AVAudioPlayer from one variable to another

Here's what I'm looking to do: I have an AVAudioPlayer called primaryPlayer playing a track, and I want it to continue uninterrupted while I transfer the player to secondaryPlayer. I'll then be using the primaryPlayer for a new AVAudioPlayer instance to play alongside the original track.
Maybe it's as simple as this:
secondaryPlayer=primaryPlayer;
primaryPlayer=[[AVAudioPlayer alloc] initWithContentsOfURL:songURL error:nil];
*these two variables are properties of the class, hence their lack of definition.
I'm worried that I may be missing something. For instance, does this code just set the two variables to point to the same memory address? So that after the second line of code, both variables correspond to the same player?
I think this may be more of an Objective C (or maybe just C) question than anything else, but thanks for reading and any "pointers" on this would be terrific! :)
Assuming that primaryPlayer player points to a valid AVAudioPlayer instance at address 0x1234 and secondaryPlayer has an arbitrary value and that both are declared as strong properties.
secondaryPlayer=primaryPlayer;
Now both variables point to the same object (at address 0x1234).
primaryPlayer=[[AVAudioPlayer alloc] initWithContentsOfURL:songURL error:nil];
secondary player still points to the same object and being a strong reference, that object is still alive. primaryPlayer now points to the newly created object, so now you have two different player objects.

Resources