TableView 在所有视图控制器中重复代码 - Swift 3

TableView repeated code in all view controllers - Swift 3

我在我的应用程序中使用了第三方 RSS 提要解析器库。我有将近 15 个页面在每个页面的表格视图中显示 RSS 提要。问题是除了 RSS 提要 link 之外,所有视图控制器都具有相同的代码。我不知道如何以这样一种方式减少代码,即所有的表视图都像它们当前工作的那样工作,同时减少代码的重复。

我使用的代码是:

import UIKit

class TopStoriesViewController: UIViewController, FeedParserDelegate, UITableViewDelegate, UITableViewDataSource {

@IBOutlet weak var tableView: UITableView!

var parser: FeedParser?
var entries: [FeedItem]?

var spinnerActivity: MBProgressHUD! = nil

override func viewDidLoad() {
    super.viewDidLoad()

    self.spinnerActivity = MBProgressHUD.showAdded(to: self.view, animated: true);
    self.spinnerActivity.label.text = "Loading";
    self.spinnerActivity.detailsLabel.text = "Please Wait!";
    self.spinnerActivity.isUserInteractionEnabled = false;

    entries = []

    DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async(execute: { () -> Void in
        self.parser = FeedParser(feedURL: topStoriesLink) // this is the link i need to change in all view controllers
        self.parser?.delegate = self
        self.parser?.parse()
    })
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
 }

// MARK: - FeedParserDelegate methods

func feedParser(_ parser: FeedParser, didParseChannel channel: FeedChannel) {
}

func feedParser(_ parser: FeedParser, didParseItem item: FeedItem) {
}

func feedParser(_ parser: FeedParser, successfullyParsedURL url: String) {
}

func feedParser(_ parser: FeedParser, parsingFailedReason reason: String) {
 }

func feedParserParsingAborted(_ parser: FeedParser) {
 }

// MARK: - Network methods
func loadImageSynchronouslyFromURLString(_ urlString: String) -> UIImage? {
}

}

请帮忙。我是 Swift 的新手。我正在使用 Swift 3.0。我需要上面显示的所有方法为每个 tableview 正确填充。

    // create super viewcontroller and write all your common code in that viewcontroller
    class ParentVC: UIViewController, FeedParserDelegate, UITableViewDelegate, UITableViewDataSource {

            @IBOutlet weak var tableView: UITableView!

            var parser: FeedParser?
            var entries: [FeedItem]?

            var spinnerActivity: MBProgressHUD! = nil

            override func viewDidLoad() {
                super.viewDidLoad()

                self.spinnerActivity = MBProgressHUD.showAdded(to: self.view, animated: true);
                self.spinnerActivity.label.text = "Loading";
                self.spinnerActivity.detailsLabel.text = "Please Wait!";
                self.spinnerActivity.isUserInteractionEnabled = false;

                entries = []

                DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async(execute: { () -> Void in
                    self.parser = FeedParser(feedURL: topStoriesLink) // This is the only thing changing in every view controller
                    self.parser?.delegate = self
                    self.parser?.parse()
                })
            }

            func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
                return entries?.count ?? 0
            }

            func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "FeedItemCell", for: indexPath) as UITableViewCell
                let item = entries![(indexPath as NSIndexPath).row]

                // image
                if let imageView = cell.viewWithTag(1) as? UIImageView {
                    if item.mainImage != nil {
                        imageView.image = item.mainImage
                    } else {
                        if item.imageURLsFromDescription == nil || item.imageURLsFromDescription?.count == 0  {
                            item.mainImage = UIImage(named: "roundedDefaultFeed")
                            imageView.image = item.mainImage
                        }
                        DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async(execute: { () -> Void in
                            for imageURLString in item.imageURLsFromDescription! {
                                if let image = self.loadImageSynchronouslyFromURLString(imageURLString) {
                                    item.mainImage = image
                                    DispatchQueue.main.async(execute: { () -> Void in
                                        imageView.image = image
                                        self.tableView.reloadRows(at: [indexPath], with: .automatic)
                                    })
                                    break;
                                }
                            }
                        })
                    }
                }

                // title
                if let titleLabel = cell.viewWithTag(2) as? UILabel {
                    titleLabel.text = item.feedTitle ?? "Untitled feed"
                }

                return cell
            }

            func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
                tableView.deselectRow(at: indexPath, animated: false)
                if let item = entries?[(indexPath as NSIndexPath).row] {

                    let nextScene = storyboard?.instantiateViewController(withIdentifier: "NewsDetailViewController") as! NewsDetailViewController

                    nextScene.newsTitle = item.feedTitle ?? "Untitled feed"
                    nextScene.newsDate = item.feedPubDate
                    nextScene.newsImgLink = item.mainImage
                    nextScene.newsDetail = item.feedContentSnippet ?? item.feedContent?.stringByDecodingHTMLEntities() ?? ""

                    nextScene.navBarTitle = "Top Stories"

                    let url =  item.feedLink ?? ""
                    nextScene.websiteURL = url

                    self.navigationController?.pushViewController(nextScene, animated: true)
                }
            }

            // MARK: - FeedParserDelegate methods

            func feedParser(_ parser: FeedParser, didParseChannel channel: FeedChannel) {
                // Here you could react to the FeedParser identifying a feed channel.
                DispatchQueue.main.async(execute: { () -> Void in
                    print("Feed parser did parse channel \(channel)")
                })
            }

            func feedParser(_ parser: FeedParser, didParseItem item: FeedItem) {
                DispatchQueue.main.async(execute: { () -> Void in
                    print("Feed parser did parse item \(item.feedTitle)")
                    self.entries?.append(item)
                })
            }

            func feedParser(_ parser: FeedParser, successfullyParsedURL url: String) {
                DispatchQueue.main.async(execute: { () -> Void in
                    if ((self.entries?.count)! > 0) {
                        print("All feeds parsed.")
                        self.spinnerActivity.hide(animated: true)
                        self.tableView.reloadData()
                    } else {
                        print("No feeds found at url \(url).")
                        self.spinnerActivity.hide(animated: true)
                        //show msg - no feeds found
                    }
                })
            }

            func feedParser(_ parser: FeedParser, parsingFailedReason reason: String) {
                DispatchQueue.main.async(execute: { () -> Void in
                    print("Feed parsed failed: \(reason)")
                    self.entries = []
                    self.spinnerActivity.hide(animated: true)
                    //show msg - feed parsing failed
                })
            }

            func feedParserParsingAborted(_ parser: FeedParser) {
                print("Feed parsing aborted by the user")
                self.entries = []
                self.spinnerActivity.hide(animated: true)
                //show msg - feed parsing aborted
            }

            // MARK: - Network methods
            func loadImageSynchronouslyFromURLString(_ urlString: String) -> UIImage? {
                if let url = URL(string: urlString) {
                    let request = NSMutableURLRequest(url: url)
                    request.timeoutInterval = 30.0
                    var response: URLResponse?
                    let error: NSErrorPointer? = nil
                    var data: Data?
                    do {
                        data = try NSURLConnection.sendSynchronousRequest(request as URLRequest, returning: &response)
                    } catch let error1 as NSError {
                        error??.pointee = error1
                        data = nil
                    }
                    if (data != nil) {
                        return UIImage(data: data!)
                    }
                }
                return nil
            }
        }

//TopStoriesViewController.swift
        // Use ParentVC instead of UIViewController      
        class TopStoriesViewController : ParentVC {
            override func viewDidLoad() {
                super.viewDidLoad()

            }

        }

//AnotherViewController.swift
        // Use ParentVC instead of UIViewController      
        class AnotherViewController : ParentVC {
            override func viewDidLoad() {
                super.viewDidLoad()

            }

        }
  • 连接你的父VC @IBOutlet weak var tableView: UITableView!从故事板

我建议:

  • 创建一个类型为 UIViewController 的基础 class 调用 - 例如 - BaseViewController 并让所有具有相同代码的视图控制器除了RSS feed link 继承自它;在其中添加所有需要的功能,默认情况下,所有子classes 应该在基础 class.

  • 中实现相同的功能
  • 要为每个视图控制器更改 url,您应该在名为 -for 的基本视图控制器中声明一个 属性 example- url 并将其值更改为当前视图控制器所需的值。请注意,这也适用于任何 属性 应该在子 class.

  • 中具有不同值
  • 为了可重用性,您应该让任何需要将其 datasource/delegate 设置为符合基础 class 的对象(例如:tableView.delegate = super.self()).

示例:

基础视图控制器:

class BaseViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    var url: String = "default url"
    var cellIdentifier: String = "cell"

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)
        return cell!
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("default implemntation")
    }
}

TopStoriesViewController(子class):

class TopStoriesViewController: BaseViewController {
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        url = "top stories url"
        tableView.dataSource = super.self()
        tableView.delegate = super.self()
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("a cell has been selected, custom implemntation")
    }
}

请注意,该示例是实现此逻辑的演示,您需要以符合您逻辑的方式实现其他功能。

希望这对您有所帮助。