我在Swift中有一个iOS应用,可以从我的网站的RSS提要中解析XML。
我希望能够显示帖子的图像并显示相关内容(目前仅显示XML代码)。
这是解析器及其控制的单元格的代码:
解析器:
import Foundation
struct RSSItem {
var title: String
var description: String
var pubDate: String
}
// download xml from a server
// parse xml to foundation objects
// call back
class FeedParser: NSObject, XMLParserDelegate
{
private var rssItems: [RSSItem] = []
private var currentElement = ""
private var currentTitle: String = "" {
didSet {
currentTitle = currentTitle.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
}
}
private var currentDescription: String = "" {
didSet {
currentDescription = currentDescription.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
}
}
private var currentPubDate: String = "" {
didSet {
currentPubDate = currentPubDate.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
}
}
private var parserCompletionHandler: (([RSSItem]) -> Void)?
func parseFeed(url: String, completionHandler: (([RSSItem]) -> Void)?)
{
self.parserCompletionHandler = completionHandler
let request = URLRequest(url: URL(string: url)!)
let urlSession = URLSession.shared
let task = urlSession.dataTask(with: request) { (data, response, error) in
guard let data = data else {
if let error = error {
print(error.localizedDescription)
}
return
}
/// parse our xml data
let parser = XMLParser(data: data)
parser.delegate = self
parser.parse()
}
task.resume()
}
// MARK: - XML Parser Delegate
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:])
{
currentElement = elementName
if currentElement == "item" {
currentTitle = ""
currentDescription = ""
currentPubDate = ""
}
}
func parser(_ parser: XMLParser, foundCharacters string: String)
{
switch currentElement {
case "title": currentTitle += string
case "description" : currentDescription += string
case "pubDate" : currentPubDate += string
default: break
}
}
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?)
{
if elementName == "item" {
let rssItem = RSSItem(title: currentTitle, description: currentDescription, pubDate: currentPubDate)
self.rssItems.append(rssItem)
}
}
func parserDidEndDocument(_ parser: XMLParser) {
parserCompletionHandler?(rssItems)
}
func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error)
{
print(parseError.localizedDescription)
}
}
单元格视图控制器:
import UIKit
class NewsTableViewController: UITableViewController
{
private var rssItems: [RSSItem]?
private var cellStates: [CellState]?
override func viewDidLoad() {
super.viewDidLoad()
tableView.estimatedRowHeight = 155.0
tableView.rowHeight = UITableView.automaticDimension
fetchData()
}
private func fetchData()
{
let feedParser = FeedParser()
feedParser.parseFeed(url: "https://appleosophy.com/feed") { (rssItems) in
self.rssItems = rssItems
self.cellStates = Array(repeating: .collapsed, count: rssItems.count)
OperationQueue.main.addOperation {
self.tableView.reloadSections(IndexSet(integer: 0), with: .left)
}
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// Return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
guard let rssItems = rssItems else {
return 0
}
// rssItems
return rssItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! NewsTableViewCell
if let item = rssItems?[indexPath.item] {
cell.item = item
cell.selectionStyle = .none
if let cellStates = cellStates {
cell.descriptionLabel.numberOfLines = (cellStates[indexPath.row] == .expanded) ? 0 : 4
}
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
tableView.deselectRow(at: indexPath, animated: true)
let cell = tableView.cellForRow(at: indexPath) as! NewsTableViewCell
tableView.beginUpdates()
cell.descriptionLabel.numberOfLines = (cell.descriptionLabel.numberOfLines == 0) ? 3 : 0
cellStates?[indexPath.row] = (cell.descriptionLabel.numberOfLines == 0) ? .expanded : .collapsed
tableView.endUpdates()
}
}
我的目标是在我的应用程序中使用一个完全本机的RSS提要,以显示带有图像和属于该文章的文本的文章。
答案 0 :(得分:0)
这个答案很晚了,但是我正在做一个类似的项目。我正在使用SwiftUI,并设法加载了远程URL。希望我的解决方案对您有所帮助:
首先加载图像
import Combine
import Foundation
class ImageLoader: ObservableObject {
var dataPublisher = PassthroughSubject<Data, Never>()
var data = Data() {
didSet {
dataPublisher.send(data)
}
}
init(urlString:String) {
guard let url = URL(string: urlString) else { return }
let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data else { return }
DispatchQueue.main.async {
self.data = data
}
}
task.resume()
}
}
然后创建一个imageView:
import Combine
import SwiftUI
struct ImageView: View {
@ObservedObject var imageLoader:ImageLoader
@State var image:UIImage = UIImage()
init(withURL url:String) {
imageLoader = ImageLoader(urlString:url)
}
var body: some View {
VStack {
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width:100, height:100)
}.onReceive(imageLoader.dataPublisher) { data in
self.image = UIImage(data: data) ?? UIImage()
}
}
}
struct ImageView_Previews: PreviewProvider {
static var previews: some View {
ImageView(withURL: "")
}
}
然后,您可以使用ImageView来查看图像:
ImageView(withURL: data.imageURL)