2017-02-13 23 views
0

Ich habe eine RSS-Feed-Parser-Bibliothek von Drittanbietern in meiner App verwendet. Ich habe fast 15 Seiten, die den RSS-Feed in Tabellenansichten auf jeder Seite anzeigen. Das Problem besteht darin, dass alle View-Controller den gleichen Code haben, mit Ausnahme der RSS-Feed-Verknüpfung. Ich weiß nicht, wie man den Code so reduzieren kann, dass alle Tabellenansichten funktionieren, während sie gerade arbeiten, während gleichzeitig die Duplizierung von Code reduziert wird.TableView wiederholten Code in allen View-Controllern - Swift 3

Der Code, den ich verwende ist:

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? { 
} 

} 

Bitte helfen. Ich bin neu in Swift. Ich benutze Swift 3.0. Ich brauche alle oben gezeigten Methoden für jede Tabellenansicht, um richtig zu füllen.

Antwort

2

Ich schlage vor, zu:

  • eine Basisklasse erstellen, vom Typ UIViewController -für Beispiel- BaseViewController und lassen Sie alle View-Controller genannt, die den gleichen Code mit Ausnahme des RSS haben Feed-Link, um davon zu erben; Fügen Sie die gesamte erforderliche Funktionalität darin hinzu, standardmäßig sollten alle Unterklassen die gleiche Funktionalität wie in der Basisklasse implementiert haben.

  • Für die url für jeden View-Controller zu ändern, sollten Sie eine Eigenschaft in der Basis View-Controller -für Beispiel- url und verändern ihren Wert zu wünschen übrig für den aktuellen View-Controller genannt erklären. Beachten Sie, dass dies auch für jede Eigenschaft angewendet werden sollte, die in der Unterklasse ihren unterschiedlichen Wert haben sollte.

  • Für Wiederverwertbarkeit, sollten Sie alle Objekte lassen damit einstellen muss seine datasource/delegate die von der Basisklasse angepasst (zum Beispiel: tableView.delegate = super.self()).

Beispiel:

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 (Unterklasse):

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

Beachten Sie, dass das Beispiel eine Demonstration der Logik ist, dies zu erreichen, Sie müssen das andere Feature implementieren in einer für Sie logischen Weise.

Hoffe das half.

+0

Wie kann ich Tabelle wie self.tableView.ReloadData() von BaseViewController neu laden? Es gibt mir mehrdeutige Fehler msg in dieser Zeile. – Mamta

+0

In diesem Fall haben Sie Abschleppoptionen: 1- Überschreiben Sie die Methode, mit der Sie die Tabellenansicht erneut laden möchten. 2- deklarieren Sie 'tableView' in der Basisklasse und verbinden Sie das IBOutlet der Komponente, wie @YogeshMakwana im Screenshot gezeigt hat. –

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

      } 

     } 
  • Ihre schwache parentVC @IBOutlet var Tableview verbinden: UITableView! von Storyboard storyboard image
+0

Wie kann ich Tabelle wie self.tableView.ReloadData() von ParentVC neu laden? Es gibt mir mehrdeutige Fehler msg in dieser Zeile. – Mamta

+1

verwenden Sie einfach self.tableView.ReloadData(), stellen Sie sicher, dass Sie @IBOutlet schwach var tableView: UITableView! Nur in ElternVC –

+0

Wie kann ich Steckdose in ParentVC machen? Ich habe 15 verschiedene Tabellenansichten? Wie verbindet man sie alle? – Mamta