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

时间:2017-02-13 10:50:07

标签: swift uitableview rss

我在我的应用中使用了第三方RSS Feed解析器库。我有近15页在每个页面的tableviews中显示RSS feed。问题是除了RSS提要链接之外,所有视图控制器都具有相同的代码。我不知道如何以这样的方式减少代码,使得所有的tableview都可以正常工作,同时减少代码的重复性。

我正在使用的代码是:

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显示上面显示的所有方法才能正确填充。

2 个答案:

答案 0 :(得分:2)

    // 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()

            }

        }
  • 连接你的parentVC @IBOutlet弱var tableView:UITableView!从故事板 storyboard image

答案 1 :(得分:2)

我建议:

  • 创建一个名为UIViewController的基类,名为-for example- BaseViewController,并让所有具有相同代码的视图控制器(从RSS源链接除外)继承它;在其中添加所需的全部功能,默认情况下,所有子类应具有在基类中实现的相同功能。

  • 要更改每个视图控制器的 url ,您应该在基本视图控制器中声明一个名为-for-example- url的属性,并将其值更改为当前的视图控制器。请注意,这也应该适用于在子类中应具有不同值的任何属性。

  • 为了可重用,您应该让具有该需求的任何对象将其datasource / delegate设置为符合基类(例如:tableView.delegate = super.self())。

示例:

BaseViewController:

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 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")
    }
}

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

希望这有帮助。