简体   繁体   English

通过委托/协议传递数据

[英]Passing data with delegates/protocols

I have a UICollectionView with a CollectionReusableView header. 我有一个带有CollectionReusableView标头的UICollectionView。 I want to pass a string from the collecitonview to the header, so that the header knows which data to load based on the string. 我想将字符串从collecitonview传递到标题,以便标题知道根据该字符串加载哪些数据。 I am trying to use delegates/protocols to do this, but keep getting "unexpectedly found nil while unwrapping an optional value." 我正在尝试使用委托/协议来做到这一点,但一直在获取“在展开一个可选值时意外发现nil”。 Here is my code: 这是我的代码:

protocol UserToQuery {
    func thisUser(x: String)
}


class Profile: UICollectionViewController {

    var ownProfile = true
    var delegate:UserToQuery?

    override func viewDidLoad() {
        super.viewDidLoad()

        if self.ownProfile == true {
            let username = PFUser.currentUser()?.username
            self.delegate!.thisUser(username!)
        }
    }
}

And here is the code for the Header view: 这是Header视图的代码:

class ProfileHeader: UICollectionReusableView, UserToQuery {

    var id1 = String()
    var controller = Profile()


    override func awakeFromNib() {
        print(id1)
        controller.delegate? = self
    }

    func thisUser(x: String) {
        self.id1 = x
        getProfileInfo()
    }

    func getUserData() {
        // code here uses the id1 value to get data
    }

}   

My understanding of delegates/protocols is this: if you want to pass data (ie, string), to another view, you make the view that receives the string conform to a protocol. 我对委托人/协议的理解是:如果要将数据(即字符串)传递给另一个视图,则使接收字符串的视图符合协议。 This protocol includes a function that is used to pass the string, and when that function is called, it notifies the other view that the string is now available for use, and then you code what you want and use the string. 该协议包括一个用于传递字符串的函数,并且在调用该函数时,它会通知另一个视图该字符串现在可供使用,然后编写所需的代码并使用该字符串。 Is that accurate? 准确吗?

In ProfileHeader , you have a variable, controller , which is creating a new instance of Profile , which is NOT the Profile view controller from your storyboard. ProfileHeader ,您有一个变量controller ,它正在创建Profile实例,而不是情节提要中的Profile视图控制器。 This is why self.delegate! 这就是为什么self.delegate! is nil in Profile.viewDidLoad() . Profile.viewDidLoad()nil

I am going to make the assumption that ProfileHeader is a view in the Profile view controller. 我将假设ProfileHeaderProfile视图控制器中的视图。 In your viewDidLoad , you should set the delegate to the ProfileHeader . viewDidLoad ,应该将委托设置为ProfileHeader See the example code below (I assume an outlet for the ProfileHeader view): 请参见下面的示例代码(我假设ProfileHeader视图有一个出口):

EDIT: ProfileHeader is not an outlet, as mentioned in the comments. 编辑: ProfileHeader不是出口,如注释中所述。 Updated my answer to reflect that. 更新了我的答案以反映这一点。

class Profile: UICollectionViewController {

    var ownProfile = true
    var delegate:UserToQuery?

    override func viewDidLoad() {
        super.viewDidLoad()

        // Set the delegate!
        self.delegate = ProfileHeader()

        if self.ownProfile == true {
            let username = PFUser.currentUser()?.username
                // Delegate won't be nil now
                self.delegate!.thisUser(username!)
            }
        }
    }
}

As a general flow, the view controller should keep references to the view, not the other way around. 作为一般流程,视图控制器应保留对视图的引用,而不是相反。 So remove the controller property from your ProfileHeader view. 因此,从ProfileHeader视图中删除controller属性。 The view shouldn't care what view controller is controlling it. 视图不应该在意哪个视图控制器正在控制它。

You have some misunderstandings about protocol/delegate, but it's normal when you start iOS development. 您对协议/委托有一些误解,但是在开始iOS开发时这是正常的。

First of all, why does the app crash : The variable delegate is an optional UserQuery . 首先,为什么应用程序崩溃:变量delegate是可选的UserQuery It's okay for a delegate to be optional, but it's never set in your code, so when you call : 委托可以是可选的,但是它从来没有在代码中设置,因此在调用时:

 self.delegate!.thisUser(username!)  

you try to force unwrapping a nil variable, which results in the crash. 您尝试强制展开nil变量,从而导致崩溃。

Protocols 通讯协定

Now, let's talk about the protocol/delegate relationship. 现在,让我们谈谈协议/代理关系。

You have an UICollectionViewController subclass, which embeds an UICollectionView object. 您有一个UICollectionViewController子类,该子类嵌入了UICollectionView对象。 This UICollectionView will be contains a mix of header, footer and cell. UICollectionView将包含页眉,页脚和单元格的混合。 Your ProfileHeader class will thus be displayed within your UICollectionView . 您的ProfileHeader类将因此显示在UICollectionView

In order to populate an UICollectionView , you don't need to create your own protocol : there are already two protocols for this : 为了填充UICollectionView ,您不需要创建自己的协议:为此已经有两个协议:

  • UICollectionViewDataSource is the main protocol to conforms to, because it allows you to populate the collection view UICollectionViewDataSource是要遵循的主要协议,因为它允许您填充集合视图
  • UICollectionViewDelegate is used for further customization of your tableview, ie customizing the appearance and handling events. UICollectionViewDelegate用于进一步定制表UICollectionViewDelegate ,即,定制外观和处理事件。

Since your Profile class inherits from UICollectionViewController you don't have to named these protocols after your class name since UICollectionViewController already conforms to these protocols as written in Apple docs 由于您的Profile类是从UICollectionViewController继承的, UICollectionViewController您不必在类名后命名这些协议,因为UICollectionViewController已经符合Apple文档中编写的这些协议

You will have to override the delegate and protocol methods in order to display some data. 您必须重写委托和协议方法才能显示一些数据。 My advice is, before using headers and footers, to use only UICollectionViewCell objects for start easily. 我的建议是,在使用页眉和页脚之前,仅使用UICollectionViewCell对象即可轻松启动。

By overriding the method -collectionView:numberOfItemsInSection: and - collectionView:cellForItemAtIndexPath: , you will be able to populate the collection view. 通过覆盖方法-collectionView:numberOfItemsInSection:- collectionView:cellForItemAtIndexPath:您将能够填充集合视图。

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

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