Picking a song and play from Music app library - Swift 2.0 - ios

I just took a basic Swift 2.0 course. I am trying to make an app to select a song from iOS's Music app library and play it. I came across this link which shows how to make media item picker.
import UIKit
import MediaPlayer
class ViewController: UIViewController {
#IBOutlet weak var pickSong: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let mediaPicker = MPMediaPickerController(mediaTypes: .Music)
// mediaPicker.delegate = self
// mediaPicker.prompt = "Select song (Icloud songs must be downloaded to use)"
mediaPicker.allowsPickingMultipleItems = false
mediaPicker.showsCloudItems = false
presentViewController(mediaPicker, animated: true, completion: {})
}
mediaPicker.delegate = self line shows
Cannot assign value of type 'ViewController' to type
'MPMediaPickerControllerDelegate?'
error message. When I blocked it, the app works and allow me to browse songs perfectly.
Question 1: I would like to know what is the use of this line?
Question 2: How to play a song that I picked using this code?
I searched here and other websites for how to play songs. I found people are using
player.play() to play music. I tried that and failed.

ViewController needs to conform to the 'MPMediaPickerControllerDelegate':
//Let other classes know ViewController is a MPMediaPickerControllerDelegate
class ViewController: UIViewController, MPMediaPickerControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let mediaPicker = MPMediaPickerController(mediaTypes: .Music)
mediaPicker.delegate = self
presentViewController(mediaPicker, animated: true, completion: {})
}
Add these methods to conform to MPMediaPickerControllerDelegate:
func mediaPicker(mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection) {
//User selected a/an item(s).
for mpMediaItem in mediaItemCollection.items {
print("Add \(mpMediaItem) to a playlist, prep the player, etc.")
}
}
func mediaPickerDidCancel(mediaPicker: MPMediaPickerController) {
print("User selected Cancel tell me what to do")
}
The purpose of
'mediaPicker.delegate = self'
is to setup ViewController to respond to the functions added above. If you don't set the delegate the mediaPicker will still present, but your ViewController won't know the user made an action.
Whenever you set a delegate, make sure the class conforms to the delegate methods. If you don't know the methods, search through Apple's Developer docs for that delegate (ie search for 'MPMediaPickerControllerDelegate') and you'll see all the delegate methods you can add.

Related

Xcode Document Picker Delegate in UIKit

Why cant I set the delegate to self? I'm running the code below in the viewcontroller.swift file, but I want to call it in a Render.swift file. I've got a metal scene running of the camera view and want to open the file picker in front of it, but it doesn't seem to be very simple.
#IBAction func importFiles(_ sender: Any) {
let documentPicker = UIDocumentPickerViewController(documentTypes: [kUTTypePlainText as String], in: .import)
documentPicker.delegate = self
documentPicker.allowsMultipleSelection = false
present(documentPicker, animated: true, completion: nil)
}
It says Cannot assign value of type 'ViewController' to type 'UIDocumentPickerDelegate
In my Renders.swift file I have a function tied to a button that calls the following:
//open dialog for picker...
let myVC: ViewController = ViewController()
myVC.importFiles()
I'm pretty new to this all.
Why cant I set the delegate to self?
Because the delegate needs to be a UIDocumentPickerDelegate, and self is not a UIDocumentPickerDelegate. You need to declare that it is:
class ViewController : UIViewController, UIDocumentPickerDelegate {
That may precipitate other issues (and I expect it will), but at least you'll get past the point where you are now.

Failing to use MPMediaPickerController

I am trying to use MPMediaPickerController for the first time, in an iOS application.
Here is the relevant code:
......
import MediaPlayer
class ViewController: UIViewController,...,MPMediaPickerControllerDelegate {
......
var mediPic_VC:MPMediaPickerController!
......
#objc func fireMediaPicker() {
if mediPic_VC == nil {
mediPic_VC = MPMediaPickerController(mediaTypes: .anyAudio)
//mediPic_VC = MPMediaPickerController(mediaTypes: .music)
mediPic_VC.delegate = self
}
self.present(mediPic_VC, animated: true, completion: nil)
}
......
// MPMediaPickerControllerDelegate protocol implementation.
func mediaPicker(_ mediaPicker: MPMediaPickerController,
didPickMediaItems mediaItemCollection: MPMediaItemCollection) {
print(#function)
}
func mediaPickerDidCancel(_ mediaPicker: MPMediaPickerController) {
print(#function)
}
// End of MPMediaPickerControllerDelegate protocol implementation.
......
}
As one can see I have a function (fireMediaPicker) to bring up the MPMediaPickerController.
But when I run it, the app shows nothing more than a white screen and the debugging console displays the message:
mediaPickerDidCancel(_:)
proving that the function mediaPickerDidCancel of the MPMediaPickerControllerDelegate protocol has been called.
Instead of the white screen I was expecting to see a list of audio items to choose from.
Beside, I have no idea why mediaPickerDidCancel is called.
What did I miss in the way I am trying to use MPMediaPickerController?
Add these to your plist:
<key>NSAppleMusicUsageDescription</key>
<string>your own string</string>

CNContactViewControllerDelegate not called when contact property selected/edited on iOS

The delegate for CNContactviewController is not called when properties get edited or selected.
When editing a new contact, the contactViewController(_ viewController: CNContactViewController, shouldPerformDefaultActionFor property: CNContactProperty) function is supposed to be called, but it's not.
How do you get notified when the user edits/selects a contact property?
Steps to reproduce:
Copy the view controller below.
Edit/select a contact
property.
Expected behavior:
"yo" is printed every time you edit/select a property.
Actual behavior:
Nothing.
import Foundation
import Contacts
import ContactsUI
class ContactViewController: UIViewController, CNContactViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
createContact()
}
func createContact() {
let contactController = CNContactViewController(forNewContact: nil)
contactController.delegate = self
contactController.allowsEditing = true
contactController.allowsActions = true
contactController.displayedPropertyKeys = [CNContactPostalAddressesKey, CNContactPhoneNumbersKey, CNContactGivenNameKey]
contactController.view.layoutIfNeeded()
present(contactController, animated:true)
}
// =============================================================================================================
// MARK: CNContactViewControllerDelegate Functions
// =============================================================================================================
func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) {
viewController.dismiss(animated: true, completion: nil)
print("hi")
}
func contactViewController(_ viewController: CNContactViewController, shouldPerformDefaultActionFor property: CNContactProperty) -> Bool {
print("yo")
return true
}
// =============================================================================================================
// MARK: UIViewController Functions
// =============================================================================================================
override var prefersStatusBarHidden: Bool {
return true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
There are three initializers for making a CNContactViewController:
Existing contact: init(for:)
New contact: init(forNewContact:)
Unknown contact: init(forUnknownContact:)
The first and third forms call the delegate method contactViewController(_:shouldPerformDefaultActionFor:). The second form does not. That's the one you are using.
With the second flavor, the only event you get is contactViewController(_:didCompleteWith:), and at that point the new contact has already been saved into the database.
When editing a new contact, the contactViewController(_ viewController: CNContactViewController, shouldPerformDefaultActionFor property: CNContactProperty) function is supposed to be called
No, it isn't. That's just an idea you made up.
Expected behavior: "yo" is printed every time you edit/select a property.
Then stop expecting that.
How do you get notified when the user edits/selects a contact property?
You don't.
When you use a framework like Cocoa, you don't get to make up any expectations you like. Your expectations need to be based on what the framework actually does. You might wish that CNContactViewController and its delegate messages worked as you describe, and that might make a very good enhancement request to Apple. But it is not how it works in fact, so expecting it to do so won't do you any good.

Open with file in swift

When you open url that contain PDF file safari ask you if you want to open it on safari or in iBook.
I want to do the same thing ,
in my project i had a collection view contains videos and photos,
i want the user to chose if he want to open the file on the app or to open it with other media player.
For loading into your own app it depends on which class you're using to display content on the exact code you'd use but for opening in another app you'd normally use a share button. Here is example code that will work if you wire up the #IBAction and #IBOutlet to the same bar button in your UI (and place a file at the fileURL that you specify):
import UIKit
class ViewController: UIViewController {
// UIDocumentInteractionController instance is a class property
var docController:UIDocumentInteractionController!
#IBOutlet weak var shareButton: UIBarButtonItem!
// called when bar button item is pressed
#IBAction func shareDoc(sender: AnyObject) {
// present UIDocumentInteractionController
if let barButton = sender as? UIBarButtonItem {
docController.presentOptionsMenuFromBarButtonItem(barButton, animated: true)
}
else {
print("Wrong button type, check that it is a UIBarButton")
}
}
override func viewDidLoad() {
super.viewDidLoad()
// retrieve URL to file in main bundle
if let fileURL = NSBundle.mainBundle().URLForResource("MyImage", withExtension: "jpg") {
// Instantiate the interaction controller
self.docController = UIDocumentInteractionController(URL: fileURL)
}
else {
shareButton.enabled = false
print("File missing! Button has been disabled")
}
}
}
Notes
A UIDocumentInteractionController is used to enable the sharing of documents between your app and other apps installed on a user's device. It is simple to set up as long as you remember three rules:
Always make the UIDocumentInteractionController instance a class
(type) property. If you only retain a reference to the controller
for the life of the method that is triggered by the button press
your app will crash.
Configure the UIDocumentInteractionController
before the button calling the method is pressed so that there is not
a wait in which the app is waiting for the popover to appear. This is important because while
the presentation of the controller happens asynchronously, the instantiation does not. And you may find that there is a noticeable delay to open the popover if
you throw all the code for instantiation and presentation inside a
single method called on the press of a button. (When testing you might see a delay anyway because the share button is likely going to be pressed almost straightaway but in real world use there should be more time for the controller to prepare itself and so the possibility of lag is less likely.)
The third rule is that you must test this on a real device not in the simulator.
More can be found in my blogpost on the subject.
Edit: Using a UIActivityViewController
Code for using UIActivityViewController instead of UIDocumentInteractionController
import UIKit
class ViewController: UIViewController {
// UIDocumentInteractionController instance is a class property
var activityController: UIActivityViewController!
#IBOutlet weak var shareButton: UIBarButtonItem!
// called when bar button item is pressed
#IBAction func shareStuff(sender: AnyObject) {
if let barButton = sender as? UIBarButtonItem {
self.presentViewController(activityController, animated: true, completion: nil)
let presCon = activityController.popoverPresentationController
presCon?.barButtonItem = barButton
}
else {
print("not a bar button!")
}
}
override func viewDidLoad() {
super.viewDidLoad()
// retrieve URL to file in main bundle
if let img = UIImage(named:"MyImage.jpg") {
// Instantiate the interaction controller
activityController = UIActivityViewController(activityItems: [img], applicationActivities: nil)
}
else {
shareButton.enabled = false
print("file missing!")
}
}
}
You can also add custom activities to the UIActivityViewController and here is code for adding an "Open In..." button to a UIActivityViewController so that you can switch to a UIDocumentInteractionController from a UIActivityViewController.
I did the same code for saving a PDF file from a URL (whether it's a local URL in your device storage, or it's a URL from somewhere on the internet)
Here is the Code for Swift 3 :
#IBOutlet weak var pdfWebView: UIWebView!
#IBOutlet weak var shareBtnItem: UIBarButtonItem!
var pdfURL : URL!
var docController : UIDocumentInteractionController!
then in viewDidLoad()
// retrieve URL to file in main bundle`
let fileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("YOUR_FILE_NAME.pdf")
//Instantiate the interaction controller`
self.docController = UIDocumentInteractionController(url: fileURL)`
and in your barButtonItem tapped method (which I have called openIn(sender)):
#IBAction func openIn(_ sender: UIBarButtonItem)
{
// present UIDocumentInteractionController`
docController.presentOptionsMenu(from: sender, animated: true)
}
FYI: You need a webView in your storyboard if you wish to show the pdf file as well
Hope this helps.

Grabbing song info from MPMediaItemPicker

I am attempting to assign the song title, author, and seconds played of a song to a set of variables. However I am unable to pull any information from the song, what would be the best way to do this as currently my way crashes.
func presentPicker (sender:AnyObject) {
//I have all of this within an IBAction if that matters, I am new to programming in general so sorry if theres any stupid mistakes
let mediaPicker = MPMediaPickerController(mediaTypes: .Music)
mediaPicker.delegate = self
mediaPicker.allowsPickingMultipleItems = false
presentViewController(mediaPicker, animated: true, completion: {println(MPMediaItemCollection())})
}
You shouldn't be using the completion argument of presentViewController:. The completion runs when the controller successfully presents, but you want to grab the song when it's finished dismissing. You need to implement this delegate method in your class:
func mediaPicker(mediaPicker: MPMediaPickerController!,
didPickMediaItems mediaItemCollection: MPMediaItemCollection!) {
println(mediaItemCollection)
}
That method will be called on your class when the user has selected a song because you set delegate equal to self. You may also want to implement this one to find out if they cancelled the picker:
func mediaPickerDidCancel(_ mediaPicker: MPMediaPickerController!)

Resources