简体   繁体   English

StoryBoard / Interface Builder中NSObject的功能是什么?

[英]what is the function of NSObject in StoryBoard / Interface Builder?

I am currently following a video tutorial course about test driven development of iOS in Swift, but when testing Table View in View Controller, I get stuck, since I don't understand why we need NSObject in Interface builder like the picture below: 我目前正在观看有关在Swift中进行iOS测试驱动开发的视频教程课程,但是在View Controller中测试Table View时,我陷入了困境,因为我不明白为什么在Interface builder中我们需要NSObject如下图所示:

Movie Library Data Service is inheritted NSObject class: 电影库数据服务继承了NSObject类:

在此处输入图片说明

the class of MovieLibraryDataService is like this: MovieLibraryDataService的类如下:

import UIKit

class MovieLibraryDataService: NSObject, UITableViewDataSource, UITableViewDelegate {

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

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


}

and the MovieLibraryDataService class will be used in XCTestCase is like this : MovieLibraryDataService将使用MovieLibraryDataService类,如下所示:

@testable import FilmFest
class LibraryViewControllerTests: XCTestCase {

    var sut: LibraryViewController!

    override func setUp() {
        super.setUp()
        // Put setup code here. This method is called before the invocation of each test method in the class.
        sut = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LibraryViewControllerID") as! LibraryViewController
        _ = sut.view
    }

    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        super.tearDown()
    }

    // MARK: Nil Checks
    func testLibraryVC_TableViewShouldNotBeNil() {
        XCTAssertNotNil(sut.libraryTableView)
    }

    // MARK: Data Source
    func testDataSource_ViewDidLoad_SetsTableViewDataSource() {
        XCTAssertNotNil(sut.libraryTableView.dataSource)
        XCTAssertTrue(sut.libraryTableView.dataSource is MovieLibraryDataService)
    }

    // MARK: Delegate
    func testDelegate_ViewDidLoad_SetsTableViewDelegate() {
        XCTAssertNotNil(sut.libraryTableView.delegate)
        XCTAssertTrue(sut.libraryTableView.delegate is MovieLibraryDataService)
    }

    // MARK: Data Service Assumptions
    func testDataService_ViewDidLoad_SingleDataServiceObject() {
        XCTAssertEqual(sut.libraryTableView.dataSource as! MovieLibraryDataService, sut.libraryTableView.delegate as! MovieLibraryDataService)
    }



}

and the definition of LibraryViewController: 以及LibraryViewController的定义:

import UIKit

class LibraryViewController: UIViewController {

    @IBOutlet weak var libraryTableView: UITableView!
    @IBOutlet var dataService: MovieLibraryDataService!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.libraryTableView.dataSource = dataService
        self.libraryTableView.delegate = dataService
    }


}

I really don't understand why I need to make that MovieLibraryDataService class 我真的不明白为什么我需要制作那个MovieLibraryDataService

I usually use: 我通常使用:

self.libraryTableView.dataSource = self
self.libraryTableView.delegate = self

but why do I need to write : 但是为什么我需要写:

self.libraryTableView.dataSource = dataService
self.libraryTableView.delegate = dataService

Edit 编辑

You can use NSObject on the Storyboard for different purposes, one of them could be also the delegation. 您可以将Storyboard上的NSObject用于不同的目的,其中之一也可以是委托。 Instead of setting it programatically like: 而不是像下面这样以编程方式设置它:

self.libraryTableView.dataSource = self
self.libraryTableView.delegate = self

you can hold control and then set the corresponding delegates like below: 您可以保持控制 ,然后按如下所示设置相应的代表:

在此处输入图片说明

Original Answer 原始答案

Because MovieLibraryDataService that conforms to UITableViewDataSource and UITableViewDelegate and not your LibraryViewController . 因为MovieLibraryDataService符合UITableViewDataSourceUITableViewDelegate而不是您的LibraryViewController

If you want to change it as you are always used to, change your code to: 如果要像往常一样更改它,请将代码更改为:

class LibraryViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet weak var libraryTableView: UITableView!
    var dataService = MovieLibraryDataService()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.libraryTableView.dataSource = self
        self.libraryTableView.delegate = self
    }

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

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

Personally I would suggest to keep it as you have it, as View Controllers tend to grow and become like we call it Massive View Controller 我个人建议保持现有状态,因为View Controller会不断增长并变得像我们称之为Massive View Controller

MovieLibraryDataService is just another class which implements UITableViewDataSource and UITableViewDelegate , with the difference that the storyboard instantiates it and that storyboard-created instance is bound via the IBOutlet @IBOutlet var dataService: MovieLibraryDataService! MovieLibraryDataService只是另一个实现UITableViewDataSourceUITableViewDelegate类,区别在于情节@IBOutlet var dataService: MovieLibraryDataService!实例化它,并且由IBOutlet @IBOutlet var dataService: MovieLibraryDataService!绑定了@IBOutlet var dataService: MovieLibraryDataService! storyboard-created实例@IBOutlet var dataService: MovieLibraryDataService! . All objects in the storyboard are storyboard-created , that's why one has to bind them to variables to use if they are not bound to other variables you use already. 情节提要中的所有对象都是storyboard-created ,这就是为什么如果对象未绑定到您已经使用的其他变量,则必须将它们绑定到要使用的变量。

Naming the variable dataService is just a fancy way of saying that it is supposed to serve , in this case as dataSource and delegate for a tableView, since it implements those delegate-protocols. 给变量dataService命名只是一种幻想的说法,因为它实现了那些委托协议,因此在本例中它应该serve tableView的dataSource and delegate

Since the dataService is instantiated by the storyboard, you could try if you can bind the dataService inside the storyboard to tableView . 由于dataService是由情节dataService实例化的,因此可以尝试是否将情节dataService绑定到tableView This is possible because you have the dataService referencable in the storyboard. 这是可能的,因为在情节dataService中有dataService引用。 This would replace setting dataSource and delegate in the viewController . 这将替换viewController中的设置dataSource and delegate

Another example 另一个例子

AppDelegate is also an NSObject inside the Storyboard so the UIApplication/NSApplication inside the storyboard is able to reference that to use, avoids having to set up AppDelegate yourself outside a storyboard. AppDelegate也是情节提要板中的NSObject ,因此情节提要板中的UIApplication/NSApplication能够引用要使用的内容,从而避免了必须在情节提要板外部设置AppDelegate自己。 (Would otherwise be ugly, maybe that's macOS only though, since mac apps have to show a Menu even if its empty.) (否则会很丑,也许只是macOS,因为Mac应用程序必须显示一个Menu即使它是空的。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM