我无法以编程方式将数据从一个UICollectionViewController传递到另一个UICollectionViewController。
目前我的设置如下:
RestaurantController
)
1A。 UICollectionViewCell(RestaurantCell
)
这个UICollectionViewCell里面有一个嵌套的UICollectionViewController和另一个自定义的UICollectionViewCell(RestaurantCollectionViewCell
)MenuController
)
2A。 UICollectionViewCell(MenuCell
)在我的RestaurantCell
里面,我正在从JSON加载数据并将其添加为一个名为restaurants的新数组:var restaurants = [RestaurantModel]()
。但是当我尝试使用MenuController
加载我的var restaurant: RestaurantModel?
中的餐馆名称或任何餐馆对象时,我得到的值为零。我感觉我的设置不正确或者我在某个地方犯了一个愚蠢的错误。也许两者。我在下面为每个课程粘贴了我的代码。
其中值在MenuController内返回nil:
print("Restaurant Name:", restaurant?.name)
print("Restaurant Id:", restaurant?.id)
自定义委托会导致问题吗?
非常感谢您的帮助和建议!
在我的RestaurantController
内:
import UIKit
import FBSDKLoginKit
class RestaurantController: UICollectionViewController, UICollectionViewDelegateFlowLayout, SWRevealViewControllerDelegate, UISearchBarDelegate, RestaurantDelegate {
var restaurantCell: RestaurantCell?
private let restaurantCellId = "restaurantCellId"
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = UIColor.qpizzaWhite()
collectionView?.register(RestaurantCell.self, forCellWithReuseIdentifier: restaurantCellId)
if self.revealViewController() != nil {
navigationItem.leftBarButtonItem = UIBarButtonItem(image: #imageLiteral(resourceName: "icon_menu_24dp").withRenderingMode(.alwaysOriginal), style: .plain, target: self.revealViewController(), action: #selector(SWRevealViewController.revealToggle(_:)))
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
}
// FIXME: issue with this...navigationcontroller is presenting, not pushing ontop of stack view
func didTapRestaurantCell(cell: RestaurantCell) {
print("Did Tap Restaurant Cell - Restaurant Controller")
let layout = UICollectionViewFlowLayout()
let controller = MenuController(collectionViewLayout: layout)
navigationController?.pushViewController(controller, animated: true)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: restaurantCellId, for: indexPath) as! RestaurantCell
cell.delegate = self
return cell
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: view.frame.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 1
}
}
在我的RestaurantCell
内:
protocol RestaurantDelegate {
func didTapRestaurantCell(cell: RestaurantCell)
}
class RestaurantCell: BaseCell, UISearchBarDelegate, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
var delegate: RestaurantDelegate?
var restaurants = [RestaurantModel]()
var filteredRestaurants = [RestaurantModel]()
private let restaurantCollectionViewCell = "restaurantCollectionViewCell"
private let activityIndicator = UIActivityIndicatorView()
lazy var searchBar: UISearchBar = {
let sb = UISearchBar()
sb.placeholder = "Search Restaurant"
sb.barTintColor = .white
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).backgroundColor = UIColor.qpizzaWhite()
sb.delegate = self
return sb
}()
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .white
return cv
}()
override func setupViews() {
super.setupViews()
collectionView.register(RestaurantCollectionViewCell.self, forCellWithReuseIdentifier: restaurantCollectionViewCell)
collectionView.delegate = self
collectionView.dataSource = self
backgroundColor = UIColor.qpizzaRed()
addSubview(searchBar)
addSubview(collectionView)
_ = searchBar.anchor(topAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, topConstant: 4, leftConstant: 4, bottomConstant: 0, rightConstant: 4, widthConstant: 0, heightConstant: 50)
_ = collectionView.anchor(searchBar.bottomAnchor, left: leftAnchor, bottom: bottomAnchor, right: rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)
loadRestaurants()
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
print(searchText)
filteredRestaurants = self.restaurants.filter({ (restaruant: RestaurantModel) -> Bool in
return restaruant.name?.lowercased().range(of: searchText.lowercased()) != nil
})
self.collectionView.reloadData()
}
// MARK - Helper Methods
func loadRestaurants() {
showActivityIndicator()
APIManager.shared.getRestaurants { (json) in
if json != .null {
// print("Restaurant JSON:", json)
self.restaurants = []
if let restaurantList = json["restaurants"].array {
for item in restaurantList {
let restaurant = RestaurantModel(json: item)
self.restaurants.append(restaurant)
}
self.collectionView.reloadData()
self.hideActivityIndicator()
}
} else {
print("Error loading JSON into Restaurant ViewController")
}
}
}
func loadImage(imageView: UIImageView, urlString: String) {
let imageUrl: URL = URL(string: urlString)!
URLSession.shared.dataTask(with: imageUrl) { (data, response, error) in
if let error = error {
print("Error loading image for Restaurant Controller:", error.localizedDescription)
}
guard let data = data, error == nil else { return }
DispatchQueue.main.async(execute: {
imageView.image = UIImage(data: data)
})
}.resume()
}
func showActivityIndicator() {
activityIndicator.frame = CGRect(x: 0.0, y: 0.0, width: 40.0, height: 40.0)
activityIndicator.center = center
activityIndicator.hidesWhenStopped = true
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.whiteLarge
activityIndicator.color = UIColor.qpizzaGold()
addSubview(activityIndicator)
activityIndicator.startAnimating()
}
func hideActivityIndicator() {
activityIndicator.stopAnimating()
}
//MARK: CollectionView Delegate & DataSource Methods
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: restaurantCollectionViewCell, for: indexPath) as! RestaurantCollectionViewCell
let restaurant: RestaurantModel
if searchBar.text != "" {
restaurant = filteredRestaurants[indexPath.item]
} else {
restaurant = restaurants[indexPath.item]
}
cell.restaurantNameLabel.text = restaurant.name
cell.restaurantAddressLabel.text = restaurant.address
if let logoName = restaurant.logo {
let url = "\(logoName)"
loadImage(imageView: cell.restaurantLogoImageView, urlString: url)
}
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if searchBar.text != "" {
return self.filteredRestaurants.count
}
return self.restaurants.count
}
//FIXME: Restaurant Name Navigation Title is still not be passed from RestaurantCell to MenuController
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Did Select Item - Restaurant Cell")
let layout = UICollectionViewFlowLayout()
let controller = MenuController(collectionViewLayout: layout)
controller.restaurant = self.restaurants[indexPath.item]
print("Controller", controller.restaurant) // Optional(QpizzaDelivery.RestaurantModel)
print("Restaurant:", self.restaurants) // [QpizzaDelivery.RestaurantModel, QpizzaDelivery.RestaurantModel, QpizzaDelivery.RestaurantModel]
print("IndexPath:", self.restaurants[indexPath.item]) // QpizzaDelivery.RestaurantModel
delegate?.didTapRestaurantCell(cell: self)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: frame.width, height: 200)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0.5
}
}
在我的MenuController
内:
import UIKit
class MenuController: UICollectionViewController, UICollectionViewDelegateFlowLayout, SWRevealViewControllerDelegate {
private let menuCellId = "menuCellId"
var restaurant: RestaurantModel?
var menuItems = [MenuItemsModel]()
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = UIColor.qpizzaWhite()
collectionView?.register(MenuCell.self, forCellWithReuseIdentifier: menuCellId)
collectionView?.alwaysBounceVertical = true
if self.revealViewController() != nil {
navigationItem.leftBarButtonItem = UIBarButtonItem(image: #imageLiteral(resourceName: "menu2-black-32").withRenderingMode(.alwaysOriginal), style: .plain, target: self.revealViewController(), action: #selector(SWRevealViewController.revealToggle(_:)))
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
print("Restaurant Name:", restaurant?.name) // returns nil
if let restaurantName = restaurant?.name {
self.navigationItem.title = restaurantName
}
loadMenuItems()
}
func loadMenuItems() {
print("Restaurant Id:", restaurant?.id) // returns nil
if let restaurantId = restaurant?.id {
print("RestaurantId:", restaurantId)
}
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: menuCellId, for: indexPath) as! MenuCell
return cell
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let layout = UICollectionViewFlowLayout()
let controller = MenuDetailsController(collectionViewLayout: layout)
navigationController?.pushViewController(controller, animated: true)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 120)
}
}
在我的MenuCell
内:
import UIKit
class MenuCell: BaseCell {
let restaurantLabel: UILabel = {
let label = UILabel()
label.text = "Restaurant King"
label.font = UIFont.boldSystemFont(ofSize: 16)
label.textColor = .black
label.numberOfLines = 0
return label
}()
let mealImageView: UIImageView = {
let iv = UIImageView()
iv.image = #imageLiteral(resourceName: "button_chicken").withRenderingMode(.alwaysOriginal)
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
return iv
}()
let mealDetailsLabel: UILabel = {
let label = UILabel()
label.text = "Grass fed grass, American cheese, and friez"
label.font = UIFont.boldSystemFont(ofSize: 12)
label.textColor = UIColor.qpizzaBlack()
label.numberOfLines = 0
return label
}()
let mealPriceLabel: UILabel = {
let label = UILabel()
label.text = "$12.00"
label.font = UIFont.boldSystemFont(ofSize: 12)
label.textColor = UIColor.qpizzaBlack()
return label
}()
let sepereatorView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.lightGray
return view
}()
override func setupViews() {
super.setupViews()
backgroundColor = UIColor.qpizzaWhite()
addSubview(restaurantLabel)
addSubview(mealImageView)
addSubview(mealDetailsLabel)
addSubview(mealPriceLabel)
addSubview(sepereatorView)
_ = mealImageView.anchor(topAnchor, left: nil, bottom: nil, right: rightAnchor, topConstant: 14, leftConstant: 0, bottomConstant: 0, rightConstant: 12, widthConstant: 60, heightConstant: 60)
_ = restaurantLabel.anchor(topAnchor, left: leftAnchor, bottom: nil, right: mealImageView.leftAnchor, topConstant: 14, leftConstant: 12, bottomConstant: 0, rightConstant: 10, widthConstant: 0, heightConstant: 20)
_ = mealDetailsLabel.anchor(restaurantLabel.bottomAnchor, left: leftAnchor, bottom: nil, right: mealImageView.leftAnchor, topConstant: 12, leftConstant: 12, bottomConstant: 0, rightConstant: 10, widthConstant: 0, heightConstant: 30)
_ = mealPriceLabel.anchor(mealDetailsLabel.bottomAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, topConstant: 10, leftConstant: 12, bottomConstant: 10, rightConstant: 10, widthConstant: 0, heightConstant: 20)
_ = sepereatorView.anchor(nil, left: leftAnchor, bottom: bottomAnchor, right: rightAnchor, topConstant: 0, leftConstant: 20, bottomConstant: 4, rightConstant: 20, widthConstant: 0, heightConstant: 1)
}
}
只需快速查看,声明一个正确类型的变量就是开始。但实际上你必须做一个赋值(=)来将数据或类引用从一个类移到另一个类。
func didTapRestaurantCell(cell: RestaurantCell) {
print("Did Tap Restaurant Cell - Restaurant Controller")
let layout = UICollectionViewFlowLayout()
let controller = MenuController(collectionViewLayout: layout)
navigationController?.pushViewController(controller, animated: true)
// you need to set the restaurant attribute of your new
// controller
let indexPath = indexPath(for: cell)
controller.restaurant = self.restaurants[indexPath.item]
}
感谢所有评论和协助我解决这个问题的人。我能够通过更改协议并将控制器作为参数传递来解决我的问题。
在RestaurantCell
:
protocol RestaurantDelegate {
func didTapRestaurantCell(cell: RestaurantCell, withMenuController: MenuController)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Did Select Item - Restaurant Cell")
let layout = UICollectionViewFlowLayout()
let controller = MenuController(collectionViewLayout: layout)
controller.restaurant = self.restaurants[indexPath.item]
delegate?.didTapRestaurantCell(cell: self, withMenuController: controller)
}
在RestaurantController
:
func didTapRestaurantCell(cell: RestaurantCell, withMenuController controller: MenuController) {
print("Did Tap Restaurant Cell - Restaurant Controller")
navigationController?.pushViewController(controller, animated: true)
}