Pass Data From View Controller to View in MVC - Swift - ios

Passing data between UIViewControllers is fairly straightforward, but passing data from a controller to a view is something I can't seem to figure out.
In my specific case the user taps on an "event" cell, and transitions into a detailed view.
How do I pass the "event" from the tapped cell, to the detail view?
// Inside Starting View Controller
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let vc = EventDetailController()
let vcView = vc.view as! EventDetailView
vcView.event = model.events[indexPath.item]
navigationController?.pushViewController(vc, animated: true)
}
// Second View
class EventDetailView: UIView {
var event: Event?
let model = EventsModel()
override init(frame: CGRect) {
super.init(frame: frame)
print("selected event: \(event)") <<<<--- Prints "nil"
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// Second Controller
class EventDetailController: UIViewController {
var eventDetailView: EventDetailView!
override func loadView() {
super.loadView()
view = eventDetailView
}
override func viewDidLoad() {
super.viewDidLoad()
}
}

You are passing data which is not the correct way to do this. You should never access the view until it's been shown or loaded correctly.
In your class EventDetailController add the property
var event: Event?
and replace this method like below
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let vc = EventDetailController()
vc.event = model.events[indexPath.item]
navigationController?.pushViewController(vc, animated: true)
}
and
override func viewDidLoad() {
super.viewDidLoad()
eventDetailView.event = self.event
}
Hope it helps
EDIT
In load view method add the following line at the start of the method
`eventDetailView = EventDetailView(frame:CGRect(x:0,y:0,width:UIScreen.main.bounds.width,height:UIScreen.main.bounds.height))`

// First View Controller
let vc = EventDetailController()
vc.eventDetailView.event = "TEST"
navigationController?.pushViewController(vc, animated: true)
// Second View
class EventDetailView: UIView {
var event: String?
var model = EventsModel()
override init(frame: CGRect) {
super.init(frame: frame)
print("selected event: \(event)")
}
override func encode(with aCoder: NSCoder) {
super.encode(with: aCoder)
aCoder.encode(event as Any?, forKey: "event")
aCoder.encode(model as Any?, forKey: "model")
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
event = aDecoder.decodeObject(forKey: "event") as? String? ?? ""
model = aDecoder.decodeObject(forKey: "model") as! EventsModel? ?? EventsModel()
}
}
// Second Controller
class EventDetailController: UIViewController {
var eventDetailView = EventDetailView()
override func loadView() {
super.loadView()
view = eventDetailView
}
override func viewDidLoad() {
super.viewDidLoad()
print(eventDetailView.event)
}
}

Related

How can I override the method of view in Controller?

I made a custom View Cell that want to reuse. I want to add action to button in customView, that show side menu. So I wrote a code ReusableCustomView.swift like below.
class ResuableCustomView: UIView {
let nibName = "ReusableCustomView"
#IBOutlet weak var categoryMenuBTn: UIButton!
#IBOutlet weak var containerView: UIStackView!
func showMenu(){
print("tapped")
}
#IBAction func menuBtnClicked(_ sender: UIButton) {
self.showMenu()
}
#IBAction func buttonTap(_ sender: UIButton) {
print("Tappedd")
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
func commonInit() {
guard let view = loadViewFromNib() else { return }
view.frame = self.bounds
self.addSubview(view)
}
func loadViewFromNib() -> UIView? {
let nib = UINib(nibName: nibName, bundle: nil)
return nib.instantiate(withOwner: self, options: nil).first as? UIView
}
}
showing SideMenu Code is like below.
func showSlideMenu(){
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let sideMenuViewController: SideMenuViewController = storyboard.instantiateViewController(withIdentifier: "SideMenuViewController") as! SideMenuViewController
let menu = CustomSideMenuNavigation(rootViewController: sideMenuViewController)
present(menu, animated: true, completion: nil)
}
The customized view is added to the storyboard and the ui is coming out well, and I want to override showMenu function so that i can show the side menu.
How Can I Override that function by code? I'd appreciate it if you could let me know.
ViewController code is below:
class categoryToViewController: UIViewController {
#IBOutlet weak var customViewCell: ResuableCustomView!
override func viewDidLoad() {
super.viewDidLoad()
}
}
storyBoard image that adopts ResuableCustomView Class
ReusableCell.xib image
You can directly add the button action menuBtnClicked inside the categoryToViewController since the ReusableCustomView is placed inside this ViewController.
class categoryToViewController: UIViewController {
#IBOutlet weak var customViewCell: ResuableCustomView!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func menuBtnClicked(_ sender: Any) {
print("pressed")
}
}
first you better inherit from UIControll instead of UIView.
Because you can get the event.
1- change define a class to this line:
class ResuableCustomView: UIControl { ... }
2- add to UIView to custom UIViewController and sed Custom class to ResuableCustomView:
3- create function in ViewController for get Event:
#IBAction private func customViewTapped(_ sender: ResuableCustomView) {
print("hello my friend :-)")
}
4- inside ResuableCustomView class set Action by append this line to your function:
self.sendActions(for: .touchUpInside)
this line send event for use.
Here I used type touchUpInside.
change your showMenu function to below code:
func showMenu(){
// set here callBack
self.sendActions(for: .touchUpInside) // and create event function with touchUpInside type
print("tapped")
}
5- now back to storyboard and connect IBAction to callBack like This Picture:
run and click on button and see print like this:
all code for CustomView:
// inheritance from UIControl instead of UIView
class ResuableCustomView: UIControl {
let nibName = "ReusableCustomView"
#IBOutlet weak var categoryMenuBTn: UIButton!
#IBOutlet weak var containerView: UIStackView!
func showMenu(){
// set here callBack
self.sendActions(for: .touchUpInside) // and create event function with touchUpInside type
print("tapped")
}
#IBAction func menuBtnClicked(_ sender: UIButton) {
self.showMenu()
}
#IBAction func buttonTap(_ sender: UIButton) {
print("Tappedd")
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
func commonInit() {
guard let view = loadViewFromNib() else { return }
view.frame = self.bounds
self.addSubview(view)
}
func loadViewFromNib() -> UIView? {
let nib = UINib(nibName: nibName, bundle: nil)
return nib.instantiate(withOwner: self, options: nil).first as? UIView
}
}
all code for ViewController:
class ViewController: UIViewController {
#IBOutlet weak var customViewCell: ResuableCustomView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction private func customViewTapped(_ sender: ResuableCustomView) {
print("hello my friend :-)")
}
}

How replace a table view by a collection view?

I want to replace a table view by a collection view, the table view is inside a tab from XLPagerTabStrip.
I already tried to replace some things but I get some errors, can someone put me on the right direction ?
import UIKit
import XLPagerTabStrip
class BooksChildViewController: UITableViewController,
IndicatorInfoProvider {
let cellIdentifier = "postCell"
var blackTheme = false
var itemInfo = IndicatorInfo(title: "Livros")
init(style: UITableViewStyle, itemInfo: IndicatorInfo) {
self.itemInfo = itemInfo
super.init(style: style)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
// MARK: - IndicatorInfoProvider
func indicatorInfo(for pagerTabStripController:
PagerTabStripViewController) -> IndicatorInfo {
return itemInfo
}
}
Your class BooksChildViewController should inherit UICollectionViewController instead of UITableViewController.
Also, you need modify your init() . UICollectionViewController can be initializer with a UICollectionViewLayout instead with a style like UITableViewController.

NSInvalidArgumentException : Workout_Tracker.QuickAddViewController collectionView:numberOfItemsInSection:]: unrecognized selector sent to instance

I have a class MenuTabs: UIView that corresponds to MenuTabs.xib. I linked them in the identity inspector. In the view is a UICollectionView. I set the UIView as the delegate and datasource for the collection view in storyboard. I'm using the MenuTabs class in a ViewController, but I keep getting this error
'NSInvalidArgumentException', reason: '-[Workout_Tracker.QuickAddViewController collectionView:numberOfItemsInSection:]: unrecognized selector sent to instance 0x7fbbe970a120'
Here are my MenuTabs and QuickAddViewController files
import UIKit
class MenuTabs: UIView {
let workoutTypes = ["", "", "", ""]
let cellId = "cellId"
#IBOutlet weak var contentView: UIView!
#IBOutlet weak var collectionView: UICollectionView!
override init(frame: CGRect) {
super.init(frame: frame)
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
if self.subviews.count == 0 {
self.setup()
}
}
func setup() {
Bundle.main.loadNibNamed("MenuTabs", owner: self, options: nil)
guard let content = contentView else { return }
contentView.frame = self.bounds
contentView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
addSubview(content)
}
}
// MARK: - Delegate and Datasource methods for UICollectionView
extension MenuTabs: UICollectionViewDelegate, UICollectionViewDataSource,
UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return workoutTypes.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath)
cell.backgroundColor = UIColor.red
return cell
}
}
import UIKit
class QuickAddViewController: UIViewController {
enum MuscleGroup: String {
case abs = "Abs"
case arms = "Arms"
case back = "Back"
case calves = "Calves"
case chest = "Chest"
case legs = "Glutes & Legs"
case shoulders = "Shoulders"
}
enum WorkoutType: String {
case bodyWeight = "Body Weight"
case weightTraining = "Weight Training"
case sportsAndRecreation = "Sports & Recreation"
case cardio = "Cardio"
}
#IBOutlet weak var workoutTypesMenu: UIView!
let exercisesData = ExerciseDatabase()
var workoutTypesDictionary = Dictionary<String,Dictionary<String,Array<String>>>()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
workoutTypesDictionary = self.exercisesData.exercisesByWorkoutType
tabBarController?.tabBar.isTranslucent = false
// Load workoutTypesMenu View
if let wtMenu = Bundle.main.loadNibNamed("MenuTabs", owner: self, options: nil)?.first as! MenuTabs? {
workoutTypesMenu.addSubview(wtMenu)
}
}
// MARK: - Get data from ExerciseDatabase.swift
// Get the workout types
func getWorkoutTypes() -> [String] {
var workoutTypesArray : [String] = []
for workoutType in workoutTypesDictionary.keys {
workoutTypesArray.append(workoutType)
}
return workoutTypesArray
}
// Get the list of muscles or options
func getMusclesOrOptions(for workoutType: String) -> [String] {
var musclesOrOptionsArray : [String] = []
let musclesOrOptions = workoutTypesDictionary[workoutType]!.keys
for muscleOrOption in musclesOrOptions {
musclesOrOptionsArray.append(muscleOrOption)
}
return musclesOrOptionsArray
}
// Get the list of exercises
func getExercisesArray(for workoutType: String, for muscleOrOption: String) -> [String] {
var exercisesArray : [String] = []
exercisesArray = workoutTypesDictionary[workoutType]![muscleOrOption]!
return exercisesArray
}
// Get the selected exercise
func getSelectedExercise(in workoutType: String, for muscleOrOption: String, at index: Int) -> String {
var selectedExercise : String = ""
selectedExercise = workoutTypesDictionary[workoutType]![muscleOrOption]![index]
return selectedExercise
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - WorkoutTypesBar and Muscles and Options Bar
// Set up the WorkoutTypes bar and the muscles and option types bar
}
Instead of setting up the delegate and datasource through the nib file, I set them in the init method of MenuTabs.swift
override init(frame: CGRect) {
super.init(frame: frame)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId)
setup()
}

swift tableView in custom view programatically - losing reference to controllers delegate and data source

I am trying to learn MVVM pattern and writing all my views programatically using Snapkit. I am creating hamburger menu which consist of simple tableView and I have a problem, that my tableView in cusom view is losing delegate and data source references on the view controller. I also tried using UITableViewController, but result is the same, here is my code:
ViewModel:
class SideMenuViewModel {
let cellId = "SideMenuCellId"
weak var delegate: SideMenuViewModelDelegate?
private let cells: [SideMenuItemStruct] = [SideMenuItemStruct(type: .allDogs, title: "ALL DOGOS"),
SideMenuItemStruct(type: .randomDog, title: "RANDOM DOGO")]
init(delegate: SideMenuViewModelDelegate) {
self.delegate = delegate
}
var numberOfRows: Int {
return cells.count
}
func selectedMenuItem(indexPath: IndexPath) {
switch SideMenuItemsEnum(rawValue: indexPath.row) {
case .allDogs?:
delegate?.selectedMenuItem(selectedItem: SideMenuItemsEnum.allDogs)
case .randomDog?:
delegate?.selectedMenuItem(selectedItem: SideMenuItemsEnum.randomDog)
default:
print("error when choosing menu item")
}
}
func cellForRow(_ tableView: UITableView, indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as? SideMenuCell else {
fatalError("could not deque Side menu cell")
}
cell.selectionStyle = .none
cell.setUpCell(sideMenuItem: cells[indexPath.row])
return cell
}
}
View:
class SideMenuView: UIView {
var sideMenuTableView = UITableView()
let sideMenuButton = UIButton(type: .system)
weak var delegate: UITableViewDelegate? {
get {
return sideMenuTableView.delegate
}
set {
sideMenuTableView.delegate = newValue
}
}
weak var dataSource: UITableViewDataSource? {
get {
return sideMenuTableView.dataSource
}
set {
sideMenuTableView.dataSource = newValue
}
}
override init(frame: CGRect) {
super.init(frame: frame)
initUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func awakeFromNib() {
super.awakeFromNib()
}
private func initUI() {
addSubview(sideMenuButton)
addSubview(sideMenuTableView)
setUpSideMenuButton()
setUpSideMenuTableView()
}
private func setUpSideMenuButton() {
sideMenuButton.setTitle("DELEGATE", for: .normal)
sideMenuButton.addTarget(self, action: #selector(buttonPrint), for: .touchUpInside)
sideMenuButton.snp.makeConstraints { (make) in
make.top.equalTo(self)
make.centerX.equalTo(self)
}
}
#objc func buttonPrint() {
print("delegate: \(String(describing: sideMenuTableView.delegate)), data source: \(String(describing: sideMenuTableView.dataSource))")
}
private func setUpSideMenuTableView() {
sideMenuTableView.snp.makeConstraints { (make) in
make.top.equalTo(sideMenuButton.snp.bottom)
make.bottom.equalTo(self)
make.left.equalTo(self)
make.right.equalTo(self)
}
}
}
And my View Controller:
class SideMenuController: UIViewController {
fileprivate let viewModel: SideMenuViewModel
fileprivate var sideMenuView: SideMenuView {
return view as! SideMenuView
}
init(viewModel: SideMenuViewModel) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
}
override func loadView() {
let sideMenuView = SideMenuView()
sideMenuView.sideMenuTableView.delegate = self
sideMenuView.sideMenuTableView.dataSource = self
view = sideMenuView
}
override func viewDidLoad() {
super.viewDidLoad()
sideMenuView.sideMenuTableView.register(SideMenuCell.self, forCellReuseIdentifier: viewModel.cellId)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension SideMenuController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.numberOfRows
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return viewModel.cellForRow(tableView, indexPath: indexPath)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
viewModel.selectedMenuItem(indexPath: indexPath)
print("awd")
}
}
Simulater after init
Simulator after scroll
DELEGATE button tapped result
I am learning from few tutorials and they didn't had this problem, but they were all using Interface builders, which I want to avoid. Please, let me know, if I am doing something really wrong, thanks.
SOLUTION
I found out, I made a really huge mistake outside of this showed code, I initialized SideMenuController in a function and didn't keep reference to it, so naturaly it was automaticly deinitialized after end of a function. It was a really bad mistake. Thanks for all answers, code here is working, but I refactored it according to answer.
I guess you have been hacking on this for a while and it looks like code has ended up a bit all over the place.
If you are going to follow MVVM then you need to think about the role of each component.
Model - An array of SideMenuItem
ViewModel - In this case it is the same as your Model so you can dispense with the Model and just use the ViewModel. In more complex examples, the ViewModel maps back to the Model, exposing on the data required by the view and performing any required translations
View - The actual visual elements; In this case just a tableview (although you also have a button for debugging)
Finally, you still have the View Controller that brings it all together
ViewModel
struct SideMenuViewModel {
let items = [SideMenuItemStruct(type: .allDogs, title: "ALL DOGOS"),
SideMenuItemStruct(type: .randomDog, title: "RANDOM DOGO")]
}
View
class SideMenuView: UIView {
weak var viewModel: SideMenuViewModel?
weak var delegate: SideMenuViewDelegate? // Was SideMenuViewModelDelegate
private let sideMenuButton = UIButton(type: .system)
private var sideMenuTableView = UITableView()
private let cellId = "YourCellID"
override init(frame: CGRect) {
super.init(frame: frame)
initUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func awakeFromNib() {
super.awakeFromNib()
}
private func initUI() {
addSubview(sideMenuButton)
addSubview(sideMenuTableView)
setUpSideMenuButton()
setUpSideMenuTableView()
}
private func setUpSideMenuButton() {
sideMenuButton.setTitle("DELEGATE", for: .normal)
sideMenuButton.addTarget(self, action: #selector(buttonPrint), for: .touchUpInside)
sideMenuButton.snp.makeConstraints { (make) in
make.top.equalTo(self)
make.centerX.equalTo(self)
}
}
#objc func buttonPrint() {
print("delegate: \(String(describing: sideMenuTableView.delegate)), data source: \(String(describing: sideMenuTableView.dataSource))")
}
private func setUpSideMenuTableView() {
sideMenuTableView.snp.makeConstraints { (make) in
make.top.equalTo(sideMenuButton.snp.bottom)
make.bottom.equalTo(self)
make.left.equalTo(self)
make.right.equalTo(self)
}
sideMenuTableView.datasource = self
sideMenuTableView.delegate = self
sideMenuTableView.register(SideMenuCell.self, forCellReuseIdentifier: cellId)
}
}
extension SideMenuView: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel?.numberOfRows ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as? SideMenuCell else {
fatalError("could not deque Side menu cell")
}
cell.selectionStyle = .none
cell.setUpCell(sideMenuItem: self.viewModel!.items[indexPath.row])
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let menuItem = self.viewModel!.items[indexPath.row]
self.delegate?.didSelect(menuItem)
}
}
ViewController
class SideMenuController: UIViewController {
fileprivate let viewModel: SideMenuViewModel
fileprivate var sideMenuView: SideMenuView {
return view as! SideMenuView
}
override func loadView() {
let sideMenuView = SideMenuView()
sideMenuView.delegate = self
sideMenuView.viewModel = viewModel
view = sideMenuView
}
init(viewModel: SideMenuViewModel) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension SideMenuController: SideMenuViewDelegate {
// TODO: Implement delegate method for menu selection
}

Acess uiviewController element from another class

there is this project im working on, but there is a problem with the element in the viewcontroller of my storyboard which i want to change its property from another class!
my first approach was instantiating an object from the viewcontroller in my second class! which returns nil at runtime!
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// let mainstampvc = MainStampVc().storyboard?.instantiateViewController(withIdentifier: "mainstampvc") as? MainStampVc
// mainstampvc?.setstampimage(imageURL: list_images[indexPath.row])
let msvc = mainstampvc()
mainstampvc?.setstampimage(imageURL: list_images[indexPath.row])
}
my second approache was instantiate the whole viewcontroller again in my second class which does nothing.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let mainstampvc = MainStampVc().storyboard?.instantiateViewController(withIdentifier: "mainstampvc") as? MainStampVc
mainstampvc?.setstampimage(imageURL: list_images[indexPath.row])
}
the whole thing i wanted is when i click on my uicollectionviewcell change the background of one of my MainViewcontroller views. here is all my classes
viewcontroller.swift
import Foundation
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var stampholder: UIView!
#IBAction func TextViewButton(_ sender: Any) {
removerSubViews()
addSubView(ViewName: "text")
}
#IBAction func AViewButton(_ sender: Any) {
removerSubViews()
addSubView(ViewName: "mohr")
}
#IBAction func BorderViewButton(_ sender: Any) {
}
#IBAction func DlViewButton(_ sender: Any) {
}
#IBOutlet weak var holderView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
addSubView(ViewName: "mohr")
let mainstampvc = self.storyboard?.instantiateViewController(withIdentifier: "mainstampvc")
let mainstampview = mainstampvc?.view
mainstampview?.frame = stampholder.frame
stampholder.addSubview((mainstampview)!)
}
func removerSubViews(){
for view in self.holderView.subviews{
view.removeFromSuperview()
}
}
func addSubView(ViewName: String)
{
if let subview = Bundle.main.loadNibNamed(ViewName, owner: self, options: nil)?.first as? UIView {
self.holderView.addSubview(subview);
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
mohrcollectionview.swift
import Foundation
import UIKit
class MohrCollectionViewController: UIView,UICollectionViewDataSource,UICollectionViewDelegate{
var mohrPath: String = ""
var fileManager: FileManager!
var list_images : [String] = []
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fileManager = FileManager.default
let currentDir = Bundle.main.resourcePath
mohrPath = currentDir!
let mohrsPath = try? fileManager.contentsOfDirectory(atPath: mohrPath + "/mohr")
list_images = mohrsPath!
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int{
return list_images.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
collectionView.register(UINib(nibName: "mohrcell", bundle: nil), forCellWithReuseIdentifier: "mohrcell")
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "mohrcell", for: indexPath) as! mohrCellController
let image = UIImage(named: list_images[indexPath.row])
cell.cellimage.image = image
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let mainstampvc = MainStampVc().storyboard?.instantiateViewController(withIdentifier: "mainstampvc") as? MainStampVc
mainstampvc?.setstampimage(imageURL: list_images[indexPath.row])
}
}
mainstampvc.swift
import Foundation
import UIKit
class MainStampVc: UIViewController{
#IBOutlet weak var stampimage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
setstampimage(imageURL: "golbanafsh.png")
}
public func setstampimage(imageURL: String)
{
stampimage.image = UIImage(named: imageURL)
}
}
any help would be appreciated
2
so here is my code with delegation but still nothing :(
//
// MohrCollectionViewController.swift
// Mohrem
//
// Created by shayan rahimian on 12/18/17.
// Copyright © 2017 shayan rahimian. All rights reserved.
//
import Foundation
import UIKit
class MohrCollectionViewController: UIView,UICollectionViewDataSource,UICollectionViewDelegate,UpdateBackgroundDelegate{
var updatedelegate:UpdateBackgroundDelegate? = nil
func updateBackground(imageURL: String) {
print("mohr update back ground e balaE")
if updatedelegate == nil {
print("no delegate")
}else{
updatedelegate?.updateBackground(imageURL: imageURL)
}
}
var mohrPath: String = ""
var fileManager: FileManager!
var list_images : [String] = []
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fileManager = FileManager.default
let currentDir = Bundle.main.resourcePath
mohrPath = currentDir!
let mohrsPath = try? fileManager.contentsOfDirectory(atPath: mohrPath + "/mohr")
list_images = mohrsPath!
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int{
return list_images.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
collectionView.register(UINib(nibName: "mohrcell", bundle: nil), forCellWithReuseIdentifier: "mohrcell")
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "mohrcell", for: indexPath) as! mohrCellController
let image = UIImage(named: list_images[indexPath.row])
cell.cellimage.image = image
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.updateBackground(imageURL: list_images[indexPath.row])
}
}
//
// MainStampvc.swift
// Mohrem
//
// Created by shayan rahimian on 12/19/17.
// Copyright © 2017 shayan rahimian. All rights reserved.
//
import Foundation
import UIKit
protocol UpdateBackgroundDelegate : class {
func updateBackground(imageURL: String)
}
class MainStampVc: UIViewController{
#IBOutlet weak var stampimage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
updateBackground(imageURL: "biggolabi.png")
}
func updateBackground(imageURL: String) {
// update your background in this funcion
print("extension")
print(imageURL)
stampimage.image = UIImage(named: imageURL)
}
}
am i doing anything wrong?
You could pass a UIViewController reference to the MohrCollectionViewController(you should call this MohrCollectionView to avoid confusion) at the time you construct it. Then whenever you need to update the background you call the relevant function on the reference.
class ViewController : UIViewController {
...
override func viewDidLoad() {
...
let view = addSubView(ViewName: "mohr")
view?.vc = self
}
func addSubView(ViewName: String) -> UIView?
{
if let subview = Bundle.main.loadNibNamed(ViewName, owner: self, options: nil)?.first as? UIView {
self.holderView.addSubview(subview);
return subview
}
}
return nil
}
class MohrCollectionView {
func updateVcBackground() {
vc?.updateBackground()
}
var vc : ViewController? = nil
}
A cleaner way to do this is use a delegate. A delegate uses a protocol to define an interface between two classes.
protocol UpdateBackgroundDelegate : class {
func updateBackground()
}
class ViewController : UIViewController, UpdateBackgroundDelegate {
...
override func viewDidLoad() {
...
let view = addSubView(ViewName: "mohr")
view?.updateBackgroundDelegate = self
}
func updateBackground() {
// update your background in this funcion
}
}
class MohrCollectionView {
func updateVcBackground() {
updateBackgroundDelegate?.updateBackground()
}
var updateBackgroundDelegate : UpdateBackgroundDelegate? = nil
}
For making the delegate work do the following:
Declare the delegate first like in Collection View Class
protocol UpdateBackgroundDelegate : class {
func updateBackground(imageURL: String)
}
Create a variable like
var updateDelegate: UpdateBackgroundDelegate?
and paste it below your collectionView class from where you want to trigger changing background colour
In the collection view selection delegate, add this line of code
updateDelegate.updateBackground(imageUrl: yourUrl)
In the View, where colour change has to take place, create your collectionView instance and add this line of code
collectionView.updateDelegate = self
At last add this extension
class ViewController :UpdateBackgroundDelegate {
func updateBackground(imageUrl: yourUrl) {
//write code to load image from url
}
}

Resources