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")
}
}
请注意,该示例是实现此逻辑的演示,您需要以符合您逻辑的方式实现其他功能。
希望这对您有所帮助。
我在我的应用程序中使用了第三方 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")
}
}
请注意,该示例是实现此逻辑的演示,您需要以符合您逻辑的方式实现其他功能。
希望这对您有所帮助。