How to pull the artist value from MPMediaItemCollection - swift

Why does the following result in a tableview full of "Artist" instead of a tableview full of actual artist names? Where did I go wrong? How do I pull the artist value from a collection? All help is appreciated...
var tableData = MPMediaQuery.artistsQuery()
override func viewDidLoad() {
super.viewDidLoad()
self.artistTableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableData.groupingType = MPMediaGrouping.Artist
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.tableData.collections!.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell = self.artistTableView.dequeueReusableCellWithIdentifier("cell")! as UITableViewCell
let artist: MPMediaItemCollection = tableData.collections![indexPath.row]
if artist.valueForProperty(MPMediaItemPropertyArtist) == nil {
cell.textLabel?.text = "Artist" as String
} else {
let artistName = artist.valueForProperty(MPMediaItemPropertyArtist) as! NSString
cell.textLabel?.text = artistName as String
}
return cell
}

You access the properties of a MPMediaItemCollection via it's representativeItem. You fetch the artist's name like so:
let artist : MPMediaItemCollection = tableData.collections![indexPath.row]
let artistName = artist.representativeItem.artist ?? "Unknown Artist"
Though if I were you I wouldn't forcibly unwrap tableData.collections because if your user has an empty iTunes library that line will case the application to crash.

Related

Alphabetic sequencing in TableView of iOS Swift 4

The original data is in JSON, which is downloaded and packed in to a Model Class called Article.swift. "article" is its element. We have
article.name = rawData["A_Name_Ch"] as! String
article.name_EN = rawData["A_Name_En"] as! String
article.location = rawData["A_Location"] as! String
article.image_URLString = rawData["A_Pic01_URL"] as? String
........
........
When showing the data on a tableviewController as below, data is sequenced by data's original sequence in JSON. It is sequenced by a key "ID". But, on Swift 4, how to sort it by AlphaBetic sequence referring to the key "article.name_EN"(in English)?
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(searchActive) {
return filtered.count
}
return articles.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ListTableCell", for: indexPath) as! ListTableCell
var article : Article
if(searchActive){ article = filtered[indexPath.row] }
else{ article = articles[indexPath.row] }
let imageURL: URL?
if let imageURLString = article.image_URLString {
imageURL = URL (string: imageURLString)
}
else { imageURL = nil }
if let c = cell as? ListTableCell {
c.nameLabel?.text = article.name;
c.name_ENLabel?.text = article.name_EN;
c.locationLabel?.text = article.location
}
}
return cell
}
You need to sort your object of the array by property name.
articles.sorted(by: { $0.name_EN > $1.name_EN })
For Asc:
articles.sorted(by: { $0.name_EN < $1.name_EN })
You have both filtered array and original array. Apply the sort on both arrays before populating to the tableView.

tableView doesn't show data in swift

I'm trying to create a tableView within a viewController. I know it is annoying, but the table looks much better that way. I am also trying to incorporate data from Firebase to put into the table. Unfortunately when I run the code, it only shows a blank table. The console was able to print the desired data, but it just won't show on the actual table. Please let me know what I'm doing wrong. Many thanks!
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var user = Auth.auth().currentUser
var users = [Users]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.reloadData()
fetchUser()
}
func fetchUser() {
Database.database().reference(fromURL: "https://yala-2018.firebaseio.com/").child("users").observe(.childAdded, with: { (DataSnapshot) in
if let dictionary = DataSnapshot.value as? [String: AnyObject] {
let user = Users()
// user.setValuesForKeys(dictionary)
user.name = dictionary["name"] as! String
user.age = dictionary["age"] as! String
user.sex = dictionary["sex"] as! String
self.users.append(user)
print(user.name, user.age)
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
}
})
}
func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return users.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "guide", for: indexPath)
let user = users[indexPath.row]
cell.textLabel?.text = user.name
cell.detailTextLabel?.text = "Age: \(user.age) Sex: \(user.sex)"
// Configure the cell...
return cell
}
func tableView(tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
}
Change this to 1 as by 0 you mean no sections which will display empty tableView even if there is a data , or remove it as by default it's 1
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}

how to delete cell and data in firebase and swift 3

I'm trying to delete the data from firebase with no luck so far. This is the code I'm using, can anyone give me a hand with it please.
class TableViewController: UITableViewController {
var ref: FIRDatabaseReference?
var grocery = [Grocery]()
override func viewDidLoad() {
super.viewDidLoad()
loadData()
}
func loadData() {
let uid = FIRAuth.auth()?.currentUser?.uid
FIRDatabase.database().reference().child("Users").child(uid!).child("Grocery").observe(.childAdded) { (snspshot: FIRDataSnapshot) in
if let dict = snspshot.value as? [String: Any] {
let Items = dict["Item"] as! String
let Quintities = dict["Quintities"] as! String
let Done = dict["Done"] as! Bool
let themBe = Grocery(Items: Items, Quintitiess: Quintities, Dones: Done)
self.grocery.append(themBe)
print(themBe)
self.tableView.reloadData()
}
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return grocery.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TasksTableViewCell") as! TasksTableViewCell
cell.titleLabel?.text = grocery[indexPath.row].Item
cell.numLabel?.text = grocery[indexPath.row].Quintities
return cell
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
self.grocery.remove(at: indexPath.row)
self.tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
----------
import Foundation
class Grocery {
var Item: String
var Quintities: String
var Done: Bool
init(Items: String, Quintitiess: String, Dones: Bool) {
Item = Items
Quintities = Quintitiess
Done = Dones
}
}
You are only deleting data for your UITableView. The logic that you need is to delete from your UITableView and Fireabase Database. As the firebase docs says you can either call removeValue, or setValue to nil or updateChildValues.
To make the deletion easier, I'd save the key of the object where the data is saved (snapshot.keys), so when you want to delete you can just get that key and perform actions.

Getting data from the selected cell (TableView)

I have a TableView with several cells of data and there are 3 labels in each cell.
How can I save all 3 label.text into another variable with indexPath
let indexPath = self.tableView.indexPathForSelectedRow
Here is the full code
I've actually asked in another post that the variable "limit" becomes null after the .observe thing.
So I'm thinking if I can get the data directly from the cell.
import UIKit
import Firebase
import FirebaseDatabase
struct limitStruct{
var name : String!
var today : String!
var limit : String!
}
class CalcViewController: UITableViewController {
var limits = [limitStruct]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
navigationController?.navigationBar.barTintColor = UIColor.black
self.title = "Calculation"
navigationController!.navigationBar.titleTextAttributes =
[NSForegroundColorAttributeName: UIColor.white]
let databaseReference = FIRDatabase.database().reference()
databaseReference.child("Limit").queryOrderedByKey().observe(.childAdded, with: {
snapshot in
var snapshotValue = snapshot.value as? NSDictionary
let name = snapshotValue!["name"] as? String
snapshotValue = snapshot.value as? NSDictionary
let today = snapshotValue!["today"] as? String
snapshotValue = snapshot.value as? NSDictionary
let limit = snapshotValue!["limit"] as? String
snapshotValue = snapshot.value as? NSDictionary
self.limits.insert(limitStruct(name:name, today:today, limit: limit), at: self.limits.count)
self.tableView.reloadData()
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return limits.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Limit")
let label1 = cell?.viewWithTag(1) as! UILabel
label1.text = limits[indexPath.row].name
let label2 = cell?.viewWithTag(2) as! UILabel
label2.text = limits[indexPath.row].today
let label3 = cell?.viewWithTag(3) as! UILabel
label3.text = limits[indexPath.row].limit
return cell!
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetails"{
let svc = segue.destination as! CirSliderViewController;
if let indexPath = self.tableView.indexPathForSelectedRow{
// svc.RsegueData =
}
}
}
}
You really don't want to be using viewWithTag(). The best way to handle this is to subclass UITableViewCell, with a property for your data model object
class LimitCell: UITableViewCell {
var limit: Limit {
didSet {
// configureCell()
}
}
}
Then in your view controller:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Limit", forIndex: indexPath) as! LimitCell
cell.limit = limits[indexPath.row]
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let svc = segue.destination as? CirSliderViewController, cell = sender as? LimitCell {
svc.RsegueData = cell.limit
}
}
It seems that you are using a callback to get the data. Does the data come from a server or is stored locally?
1) If the data comes from a server, you code cannot guarantee that var limits already got the data when the func prepare is called.
2) If the data is stored locally, and ONLY limitis nil, you must check whether or not you correctly assign limits[indexPath.row].limit to limits to the cell.(Is it nil at this moment?) I think the problem is in func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) where limit is saved.
By the way, the more practical and efficient way to implement func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) is that:
Lets say the your custom cell is call LimitCell and has three UILabels: var label1, var label2, var label3.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Limit") as! LimitCell
cell.label1.text = limits[indexPath.row].name
cell.label2.text = limits[indexPath.row].today
cell.label3.text = limits[indexPath.row].limit
return cell
}

How do I get the value from the model to the controller

This is my first program using MVC design pattern, I'm stuck how to get the values from the model to my controller and to display it in my view. I'll show you what I have done. Kindly clarify me what I did wrong? Or show me how it can be done in other way around.
Model
class songData: NSObject {
var artistName: String
var albumName: String
init(artistName: String, albumName: String) {
self.artistName = artistName
self.albumName = albumName
}
}
Controller
#IBAction func doTheSearch(sender: AnyObject) {
itunesAPI().itunesSearch({(song : songData) in
})
self.tableView.reloadData()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return song1.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
var artistAndAlbum = itunesAPI().array[indexPath.row]
cell.textLabel?.text =
cell.detailTextLabel?.text =
return cell
}
API
func itunesSearch(completionHandler:(songData)->()) {
Alamofire.request(.GET, "http://itunes.apple.com/search?", parameters: ["term" : "tamil new songs", "media" : "music"])
.responseJSON { (response) in
let json = JSON(response.result.value!)
if let jsonData = json["results"].arrayObject {
self.array = jsonData as! [[String : AnyObject]]
if self.array.count > 0 {
// self.array = jsonData as! [[String : AnyObject]]
// if let resultsDict = resultsArray.first {
let albumName = json["results"]["collectionName"].stringValue
let artistName = json["results"]["artistName"].stringValue
let song = songData(artistName: artistName, albumName: albumName)
completionHandler(song)
}
}
I do have the nothing on my view except the story board which consists of a table view with a single cell. I need to get the response from the API and show it in the view.
First, you're going to want to reload your table after the data is returned. Update your IBAction to this:
itunesAPI().itunesSearch({(song : songData) in
self.tableView.reloadData()
})
Otherwise reloadData will get called before the data is returned. Set a property on the viewController to house the data. Also, it's good practice to start a class name with a capital letter.
var tableData:[SongData] = [SongData]()
Then set this variable when the data successfully returns:
itunesAPI().itunesSearch({(song : songData) in
self.tableData.append(song) // add the result to the list of data
self.tableView.reloadData() // reload the table
})
Then set the cells as so:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
var artistAndAlbum = self.tableData[indexPath.row]
cell.textLabel?.text = artistAndAlbum.artistName
cell.detailTextLabel?.text = artistAndAlbum.albumName
return cell
}