Grabbing song info from MPMediaItemPicker - ios

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!)

Related

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>

Refactoring CNContactPicker UI Code using the delegate pattern in Swift

I have implemented the CNContactPickerViewController ContactsUI provided by iOS in iOS10 succesfully in a view controller so I can have a user select multiple contacts to invite to an event. I am trying to reduce the size of this single view controller by implementing the delegate pattern, and am stuck on a black screen. I have looked at a few resources, and think I am calling the delegate and defining the protocol accordingly. I have a view controller, CreateEventViewController and it implements my self defined ContactsToInviteDelegate. This protocol is as follows:
protocol ContactsToInviteDelegate : class {
//array of array of KV-pairs where inner array is {"email":"email#gmail.com", "phone": "+18965883371"}
//array of JSON objects to upload
func contactsToInvite(_ contactsStructure: [[String:String]])
}
My ContactPickerViewController self defined class is as follows:
class ContactPickerViewController: UIViewController, CNContactPickerDelegate {
//class variables
let phoneNumberKit = PhoneNumberKit()
weak var delegate: ContactsToInviteDelegate?
var contactsToSendInvitesTo = [[String:String]]()
func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) {
contacts.forEach { contact in
let phoneNum = contact.phoneNumbers.first
var stringPhoneNumber = String()
do{
let phoneNumber = try self.phoneNumberKit.parse((phoneNum?.value.stringValue)!, withRegion: "US", ignoreType:true)
stringPhoneNumber = "+1\(phoneNumber.adjustedNationalNumber())"
print(stringPhoneNumber)
}
catch {
print("phone number parsing error")
}
let contactDisplayName = contact.givenName
print("displayName: \(contactDisplayName)" )
let contactEmail = contact.emailAddresses.first?.value ?? ""
print("email: \(contactEmail)")
self.contactsToSendInvitesTo.append(["email":contactEmail as String, "phone":stringPhoneNumber])
}
delegate?.contactsToUpload(self.contactsToSendInvitesTo)
}
func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
print("cancel contact picker")
}
func contactPicker(_ picker: CNContactPickerViewController,didSelectContactProperties contactProperties: [CNContactProperty]) {
}
}
And in the CreateEventViewController I am calling the delegate when i click the invite users button and implementing the method of the protocol to just attempt to print the final structure displaying contacts emails and phone numbers to send invitations to:
func selectContactsPicker() {
let cnPicker = ContactPickerViewController()
cnPicker.delegate = ContactPickerViewController() as? ContactsToInviteDelegate
self.present(cnPicker, animated:true, completion:nil)
}
func contactsToInvite(_ contactsStructure: [[String : String]]) {
print(contactsStructure)
}
This code without refactoring to try to use the delegate pattern worked before. I had all these functions within one single view controller, but with all the logic required this file itself is extending beyond 400+ lines. My problem now is that after attempting to refactor using the delegate pattern, when i click the button to trigger selectContactsPicker all I see is a black screen. I don't know what I am doing wrong, but I have a feeling it is this function itself. I am not quite sure what the body of this function should be in order to delegate the responsibility to the correct controller, or how to display it properly. Examples I saw used storyboards and segues, such as this. I looked at other examples for using delegates but I think my problem is a bit too specific and I don't know how to ask in a more general sense. If I did, I would probably not have this problem to begin with, as then I would probably properly understand how to implement the delegate pattern.
A delegate does not have to be a view controller. This is a convenient pattern when a view controller manages elements requiring delegates - rather than instantiate separate objects just let the view controller implement the protocol.
There are a number of ways to manage unruly view controllers which grow too large.
One simple way is to use extensions. To add a delegate protocol to an existing view controller:
extension SomeViewController : CNContactPickerDelegate {
... implement contact picker delegate methods
}
This can nicely compartmentalise your source code making it easier to read.
If you want to use a separate class instance as the delegate, that can be done quite easily too.
Declare your delegate class, either in the same source file or another:
class MyPickerDelegate : NSObject, CNContactPickerDelegate {
... implement contact picker delegate methods
}
note the class must inherit from NSObject, but does not need to be a UIViewController.
In the code where you fire up the contact picker:
picker = CNContactPickerViewController()
self.pickerDelegate = MyPickerDelegate()
picker.delegate = self.pickerDelegate
self.present(picker, animated: true)
Note picker view controller only keeps a weak reference to the delegate, so you must make sure to keep a strong reference to the object somewhere. Here I am using a property pickerDelegate

XCode8 Swift3 - Problems with open contact list and retrieve data by click

Currently I'm developing my first iOS App and I'm a little slow and rude about the code (it's so weird and different from java) and, if this was the only problem, with the new update, Xcode is making my code insane. I think I solved most of the issues but...
Before, on one of the screens, the app opened a the address book and let the user click on one; when the clicked was done, the contact list close and data from that contact was retrieved to the controller. Now, if the user click on a contact, more info is displayed but any information come out of the console log.
I try everything I find on net and I'm not sure why is not working.
Before, I use Addressbook (or something like that) but I already tried with CNContact.
This is the Button code
#IBAction func addNewContactOnClick(_ sender: AnyObject) {
let peoplePicker = CNContactPickerViewController()
peoplePicker.delegate = self
self.present(peoplePicker, animated: true, completion: nil)
}
CNContactPickerDelegate methods
func contactPicker(picker: CNContactPickerViewController, didSelectContacts contacts: [CNContact]){
contacts.forEach { contact in
for number in contact.phoneNumbers {
let phoneNumber = number.value as! CNPhoneNumber
print("number is = \(phoneNumber)")
}
}
}
func contactPickerDidCancel(picker: CNContactPickerViewController) {
print("Cancel Contact Picker")
}
Methods of CNContactPickerDelegate is changed in Swift 3 like below.
func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) {
//your code
}
func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
//your code
}
For other methods of CNContactPickerDelegate check Apple Documentation.

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

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.

Capturing and storing a picture with UIImageWriteToSavedPhotosAlbum()

I'm trying to capture and save a picture using the UIImageWriteToSavedPhotosAlbum() funciton. Here is the code I have right now.
#IBAction func CameraAction(sender: UIButton) {
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .Camera
presentViewController(picker, animated: true, completion:nil)
So essentially I created an object called picker with the UIImagePickerController() class. I want to use the UIImageWriteToSavedPhotosAlbum() function so that I can save the photo that was just taken with the code above to the photo album. I know there are 4 parameters in total that I need to use in order to correctly use the UIImageWriteToSavedPhotosAlbum() function. I figured for the 2nd, 3rd, and 4th parameter I can set it to nil. I'm mainly confused about the first parameter. I know its supposed to be a UIImage. How to I get the picture I just took with the code above as a UIImage?
Add UIImagePickerControllerDelegate delegate tinyour viewcontroller class
Implement the completion method
func imagePickerController(picker:UIImagePickerController!, didFinishPickingMediaWithInfo info:NSDictionary)
{
if(picker.sourceType == UIImagePickerControllerSourceType.Camera)
{
// Access the uncropped image from info dictionary
var imageToSave: UIImage = info.objectForKey(UIImagePickerControllerOriginalImage) as UIImage
UIImageWriteToSavedPhotosAlbum(imageToSave, nil, nil, nil)
self.dismissViewControllerAnimated(true, completion: nil)
}
}

Resources