Apologies
You must be signed in to watch this lesson.
Parsing RSS XML Feed with FeedKit
Podcasts
Podcasts are published as a blob of information on the internet, usually formatted in XML format. Unfortunately this is considerably harder to parse compared to JSON. XML isn't as popular anymore as it is not as humanly readable and simple compared to JSON. Anyhow, let me show you how to use a popular library through Cocoapods to quickly and easily parse XML into usable Swift objects.

Comments (13)
Kilian Hiestermann
6 years ago
Do you have an idea why they are using a switch statement and not an enum?
Tube
6 years ago
If you mean in the XML parsing code, they are switching on the enum from FeedKit.
Brian Voong
6 years ago
Tokyojogo
6 years ago
Hi Brian, is it ok or good practice to put all that code inside the switch statement?
Brian Voong
6 years ago
Prabhdeep Singh Randhawa
6 years ago
Morning brian, We dont need break for weekends
Brian Voong
6 years ago
이동건
6 years ago
hello brian. i got some warning messages said [Common] _BSMachError: port 776f; (os/kern) invalid capability (0x14) "Unable to insert COPY_SEND" it only appears when i clicked your podcasts and it gave me whole correct data but it had some delay when view changes what is the problem?
Brian Voong
6 years ago
이동건
6 years ago
Thanks a lot!! :)
Alex Alx
5 years ago
Hey Brian. I have a question. Why didn't you append directly to the Episode object ?
Brian Voong
5 years ago
Alex Alx
5 years ago
I was doing the performance testing right now and that's why I was wondering. Thanks for the extremely quick reply.
sashensingh
5 years ago
Hey Brian, seems like this line let parser = FeedParser(URL: url) causes a slight delay when segue'ing from PodcastSearchController seems to hang a bit then present the EpisodeController...will continue your course but not sure if you resolve this issue further on
Dew Douglass
5 years ago
Same
nombienombie
5 years ago
Hey Brian, how would you recommend dealing with http only feed urls? It's difficult to whitelist as I do not know up front what podcat a user has searched for
nombienombie
5 years ago
Please ignore this question, you just solved it right at the end of the video :)
humbleCoder
5 years ago
Hey Brian, so I received this error when searching for podcasts. All the podcasts show up in my search results, so the app is working as it should. I couldn't find anything on google about it though. Has anyone else ran into this issue? 2018-05-18 07:50:21.068445-0400 Podcasts[10491:890498] Task <5EC71475-10D8-48E4-A52A-70F82C4D1ACD>.<82> finished with error - code: -999
humbleCoder
5 years ago
UPDATE: It seems to happen when I use SDWebImage. As soon as I comment this line out: //podcastImage.sd_setImage(with: url, completed: nil) That error message stops showing up. Should I report as a bug?
Brian Voong
5 years ago
aps17
5 years ago
Hey Brian, I am getting this error when I try to run the app on a real device. It works perfectly fine on the simulator. I have everything required in the info.plist CredStore - performQuery - Error copying matching creds. Error=-25300, query={ class = inet; "m_Limit" = "m_LimitAll"; "r_Attributes" = 1; sync = syna; }
Pavlos Nicolaou
5 years ago
The problem seems to be with the App Transport security, after enabling it, it worked fine with the following sets of code in iOS 11, Also the above URL that you have provided seems to have associated https link, please use either https link or allow App Transport security
Dew Douglass
5 years ago
What do we do for feeds that are not https
Dew Douglass
5 years ago
whoops. delete delete comment
Pavlos Nicolaou
5 years ago
Hi Brian, I think the RSS Feed is not always available as https. I tried Accidental Podcast and it is not showing any of the episodes because it is not https
Brian Voong
5 years ago
gottaminute
5 years ago
Hi Brian, I have search Google, but I'm still having some problem trying to get the collectionView to refresh on pull. Here is my code... lazy var refresher: UIRefreshControl = { let refreshControl = UIRefreshControl() refreshControl.attributedTitle = NSAttributedString(string: "Fetching Image Data ...") refreshControl.addTarget(self, action: #selector(refreshImageData), for: .valueChanged) //self.collectionView?.refreshControl = refreshControl return refreshControl }() override func viewDidLoad() { super.viewDidLoad() setupCollectionView() fetchJSON() } fileprivate func setupCollectionView() { self.tabBarItem.title = "title" collectionView?.backgroundColor = .white collectionView?.register(NewImageCell.self, forCellWithReuseIdentifier: cellId) collectionView?.refreshControl = refresher } @objc private func refreshImageData() { // Fetch Weather Data print("refreshing image list") fetchJSON() DispatchQueue.main.async() { self.collectionView?.reloadData() } refresher.endRefreshing() } It looks as if everything is working. Yet the data stays the same, it will not pull the new data from the json file that I call in fetchJSON(). Seems like the cache will not update. What do you think could be the problem?
Brian Voong
5 years ago
gottaminute
5 years ago
Hi Brian, I've been trying to implement a completionHandler to work with a pull down refresh, but it doesn't seem to refresh the list. Can you please review my code and let me know where I went wrong? // // NewController.swift // GraphicsFactoryFeed // // Created by ROB GILLEN on 8/12/18. // Copyright © 2018 ROB GILLEN. All rights reserved. // import UIKit import SDWebImage import SafariServices class NewController: UICollectionViewController, UICollectionViewDelegateFlowLayout { fileprivate let cellId = "cellId" var courses = [Course]() lazy var refresher: UIRefreshControl = { let refreshControl = UIRefreshControl() refreshControl.attributedTitle = NSAttributedString(string: "Updating New Images...") refreshControl.addTarget(self, action: #selector(refreshImageData), for: .valueChanged) //self.collectionView?.refreshControl = refreshControl return refreshControl }() override func viewDidLoad() { super.viewDidLoad() setupCollectionView() reloadCollection() } fileprivate func setupCollectionView() { collectionView?.backgroundColor = .white collectionView?.register(NewImageCell.self, forCellWithReuseIdentifier: cellId) collectionView?.refreshControl = refresher } struct Course: Decodable { let id: Int let title: String let url: String let link: String let description: String } @objc private func refreshImageData() { // Fetch Weather Data print("updating image list") reloadCollection() let timer = DispatchTime.now() + .milliseconds(500) DispatchQueue.main.asyncAfter(deadline: timer) { self.refresher.endRefreshing() } } func reloadCollection() { fetchJSON { json, error in } } fileprivate func fetchJSON(completionHandler:@escaping ([Course]?, Error?)->Void) { let urlString = "https://www.graphicsfactory.com/json_two.json" guard let url = URL(string: urlString) else { return } URLSession.shared.dataTask(with: url ) { (data, _, err) in DispatchQueue.main.async { if let err = err { print("failed to get data:", err) return } guard let data = data else { return } do { let decoder = JSONDecoder() self.courses = try decoder.decode([Course].self, from: data) //print(courses) //print("refreshing images") completionHandler(self.courses,nil) self.collectionView?.reloadData() } catch let jsonErr { print("error:", jsonErr) } } }.resume() // Do any additional setup after loading the view, typically from a nib. } // MARK:- UICollectionView Delegate / Spacing Methods override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { //return 5 return courses.count } override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as? NewImageCell else { fatalError("Wrong cell class dequeued") } self.navigationItem.title = "\(courses.count) New Images" let course = courses[indexPath.row] let url = URL(string: course.url) //print (url) cell.imageView.sd_setImage(with: url, completed: nil) //cell.backgroundColor = .red return cell } override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { let course = courses[indexPath.row] let config = SFSafariViewController.Configuration() config.entersReaderIfAvailable = false if let url = URL(string: course.link) { let vc = SFSafariViewController(url: url, configuration: config) present(vc, animated: true) } // if UIApplication.shared.canOpenURL(url!) { // UIApplication.shared.open(url!, options: [:], completionHandler: nil) // } } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let width = (view.frame.width - 5 * 16) / 3 return CGSize(width: width, height: width) } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { return UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16) } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { return 16 } }
gottaminute
5 years ago
Hi Brian, I ended up just using the clear cache function of SDWebImage within the pull down to refresh function... SDImageCache.shared().clearMemory() SDImageCache.shared().clearDisk() That seems to do the job. Do you see any problems of doing this?
albaqawi
5 years ago
gottaminute, you are hitting good points. I am trying to implement the same thing but I cannot follow your reasoning.... can you share a repo for this stage of your project?
Lucrecio909
4 years ago
Hello Brian do you have any resources to be able to play the Itunes "previewUrl"? Thank you im working on a music app.
HELP & SUPPORT