Make UIImageView accessible from all viewControllers - ios

My question is, how can I make it so redDot and wCircle can be accessed from the Second viewController so they can become hidden or not hidden. They are not connected directly, but you can get to them with different viewControllers.
First viewController
class SecondViewController: UIViewController
{
#IBOutlet weak var redDot: UIImageView!
#IBOutlet weak var wCircle: UIImageView!
}
Second viewController
class ProgressViewController: UIViewController {
#IBOutlet weak var rDot: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
rDot.isUserInteractionEnabled = true
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(rdotimageTapped(tapGestureRecognizer:)))
rDot.addGestureRecognizer(tapGestureRecognizer)
view.bringSubview(toFront: rDot)
}
func rdotimageTapped(tapGestureRecognizer: UITapGestureRecognizer) {
wcircle.isHidden = true
redDot.isHidden = false
view.layoutIfNeeded()
print("It worked")
}

Im not sure if this is a right way but what I would do is have a reference of UIImageView in my second VC and then set that to the imageView of my first VC.
So add these two in your "ProgressViewController"
var redDot: UIImageView?
var wCircle: UIImageView?
and then in your prepare for segue pass your current UIImageView.
let progressViewController = segue.destination as! ProgressViewController
progressViewController.redDot = self.redDot
progressViewController.redDot.wCircle = self.wCircle

You can achieve that by adding a new member to your second and third view controllers, this member is a closure:
var updateFirstViewControllerImageViews: (() -> Void)?
Then override prepare for segue method of your firstViewController, and set updateFirstViewControllerImageViews for each of your second and third view controller like this:
secondViewController.updateFirstViewControllerImageViews = {
// Update your image views here in the way you want!
}
Now, in your second and third view controllers you can use that closure wherever you want like this:
self.updateFirstViewControllerImageViews?()

Related

What should I change in my code to make textfield in cell not to be nil after dismiss VC

Community!
I have some issue.
code:
protocol CellDelegate: class { }
class Cell: UITableViewCell {
.....
#IBOutlet weak var valueTextField: UITextField!
weak var delegate: CellDelegate?
.....
}
didSelectRowAt indexPath presents my ContainerView by overFullScreen, where I have:
class ContainerViewController: UIViewController {
.....
#IBOutlet private weak var fromTextField: UITextField!
#IBOutlet private weak var toTextField: UITextField!
#IBAction private func performChange(_ sender: UIButton) {
if let from = Int(fromTextField.text!), let to = Int(toTextField.text!) {
let cell = Cell()
cell.delegate = self
cell.valueTextField = "\(from) - \(to)"
self.dismiss(animated: false, completion: nil)
}
}
.....
}
extension ContainerViewController: CellDelegate { }
printDebug tells me that performChange sending my data well to other class, but cell.valueTextField is being nil when ContainerViewController dismiss and app crash
I know that I can make valueTextField.text = "1 - 5" //example from 1 to 5
with help of alert, but I need to make it with other viewController.
Please help me
You shouldn't use
let cell = Cell()
but instead add a delegate to the previous vc when you present the containervc (inside didSelectRowAt) and send the data before the dismiss , then change the array model of the table and finally refresh the table

Using shared classes for different views

I have an onboarding user flow:
Name -> Age -> Gender
Each of the screens shares the same structure:
Question (top)
Input (middle)
Continue (bottom)
I have a class OnboardingHelper.swift that creates a class to set the question box and continue button:
class UserOnboardingHelper{
var text: String
var questionbox: UIView
var viewController: UIViewController
var continueButton: UIButton
init(text: String, questionbox: UIView, viewController: UIViewController, continueButton: UIButton){
self.text = text
self.questionbox = questionbox
self.viewController = viewController
self.continueButton = continueButton
}
func setQuestionBox(){
//sets question box
}
func setContinueButton(){
//sets continue button
enableContinueButton()
addContinueButtonPath()
}
func enableContinueButton(){
//enables continue button
}
func disableContinueButton(){
//disables continue button
}
func addContinueButtonPath(){
//sets path of continue button based on which view
}
}
In each of the onboarding ViewControllers I am setting the class in ViewDidLoad():
class NamePageViewController: UIViewController, UITextFieldDelagate {
#IBOutlet weak var questionbox: UIView!
#IBOutlet weak var continueButton: UIButton!
#IBOutlet weak var inputLabel: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
let namePageSettings = UserOnboardingHelper(text: "What is your name", questionbox: questionbox, viewController: self, continueButton: continueButton)
namePageSettings.setQuestionBox()
namePageSettings.setContinueButton()
inputLabel.delegate = self
if nameIsFilled {
namePageSettings.enableContinueButton()
} else{
namePageSettings.disableContinueButton()
}
}
}
The issue is that in the ViewController I textFieldDidEndEditing() function which needs to call the namePageSettings class from viewDidLoad()
func textFieldDidEndEditing(_ textField: UITextField){
if (textField.text?.empty)!{
//I want to call disableContinueButton() from UserOnboardingHelper
} else {
//I want to enable enableContinueButton() from UserOnboardingHelper
}
}
Trying to understand if:
The overall approach is correct and if not, what's the best way
If the above approach is in the right direction, how should disableContinueButton() and enableContinueButton() be called?
Thanks in advance! Sorry if the approach is really dumb - I'm still trying to wrap my head around classes.
You can have the view controller have a weak reference to the onboarding helper, so you can still call helper methods without creating a retain cycle.
In NamePageViewController, add a property:
weak var userOnboardingHelper: UserOnboardingHelper?
Then, in UserOnboardingHelper's initializer, add:
self.viewController.userOnboardingHelper = self
You can now call the onboarding helper's methods in the view controller:
userOnboardingHelper.disableContinueButton()
userOnboardingHelper.enableContinueButton()

Change image color with tapGesture on different viewController

I am trying to get the UIImageView wCircle to change to red when the UIImageView on a different viewController rDot is tapped. The problem is, when I tap rDot I get the error Thread 1: EXC_BAD_INSTRUCTION (code = EXC_I386_INVOP subcode = 0x0) I made wCircle a global variable so it could be reached in the other viewController.
First viewController
weak var wCircle: UIImageView!
class SecondViewController: UIViewController {
#IBOutlet weak var wCircle: UIImageView!
}
Second viewController
class ProgressViewController: UIViewController {
#IBOutlet weak var rDot: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
rDot.isUserInteractionEnabled = true
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(rdotimageTapped(tapGestureRecognizer:)))
rDot.addGestureRecognizer(tapGestureRecognizer)
}
func rdotimageTapped(tapGestureRecognizer: UITapGestureRecognizer) {
wCircle.image = wCircle.image!.withRenderingMode(.alwaysTemplate) //error on this line
wCircle.tintColor = UIColor.red
}
}
you code is not organized and indicate nothing Any way
change this line of code
replace weak var wCircle: UIImageView!
with
weak var wCircle = UIImageView()
and this
func rdotimageTapped(tapGestureRecognizer: UITapGestureRecognizer) {
wCircle?.image = whiteDot.image!.withRenderingMode(.alwaysTemplate) //error on this line
wCircle?.tintColor = UIColor.red
}
wCircle is weak variable and it is optional value.So when you are calling it from other class it can't be optional. Also make it strong variable

Swift 3 pass values to Controller on UICollectionViewCell button click

I am beginner in iOS development and I have implemented following screen using UICollectionView :
CollectionViewCell File Code is:
import UIKit
class EventCell: UICollectionViewCell{
var classEvent: Event?
#IBOutlet weak var eventTitle: UILabel!
#IBOutlet weak var eventTeams: UILabel!
#IBOutlet weak var eventTime: UILabel!
#IBOutlet weak var eventTeamOneImage: UIImageView!
#IBOutlet weak var eventTeamTwoImage: UIImageView!
#IBOutlet weak var leaderboardButton: UIButton!
var datasourceItem: Any?{
didSet{
guard let event = datasourceItem as? Event else { return }
classEvent = event
eventTitle.text = "Match \(event.matchNo) (\(event.matchStage))"
eventTeams.text = "\(event.teamOne.nameAttr) vs \(event.teamTwo.nameAttr)"
eventTime.text = "\(event.getEventLockTimeAsString())"
eventTeamOneImage.loadImageUsingCache(withUrl: event.teamOne.flagPhoto)
eventTeamTwoImage.loadImageUsingCache(withUrl: event.teamTwo.flagPhoto)
leaderboardButton.addTarget(self, action: #selector(handleLeaderBoardClick), for: .touchUpInside)
}
}
#IBAction func leagueButton(_ sender: Any) {
}
weak var delegate: HomeControllerDelegate?
func handleLeaderBoardClick() {
if let matchId = classEvent?.id {
print(matchId)
delegate?.clickOnLeaderBoard(matchId: matchId)
}
}
}
Now on click on Leaderboard button(icon with 1,2,3) I would like to open new LeaderBoard Controller and pass matchId which is classEvent.id
How can I pass values to the new controller? And what is the best way to do that.
You can pass the match Id via segue:
In LeaderBoard Controller set a property:
var matchId:Int?
Set a segue between the controller and add an identifier:
On Click leaderboard button:
self.performSegueWithIdentifier("yourSegueIdentifier", sender: self)
Add the segue method:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue,identifier == "yourSegueIdentifier" {
let destinationVC = segue.destinationViewController as LeaderbardController
destinationVC.matchId = classEvent.id
}
}
}
Three easy steps to get what u want:
Make a BaseViewController class a subclass of UiViewController. This class would be the alternate of UiViewcontroller in your project,it means while creating any viewcontroller BaseViewController will be the parent class.
Declare a variable in BaseViewController.e.g- var data: Any?
Then while moving from a viewcontroller to another , simply assign any type of data to that variable declared in BaseViewController.
And in any lifecycle method of your new viewcontroller you will get that data using self.data.

Pass Image from UITabBarController to subview (Swift)

I am using Xcode 6 with swift.
I am trying to pass an image / UIImage from my UITabBarController to one of the subviews (tabs). The Image itself is being passed to the UITabBarController using the loadImage function (which is in return called by another UIViewController during prepareForSegue).
//this is the tab bar controller
class DesignerTabBarController : UITabBarController{
var pickedImage : UIImage = UIImage() //empty image
var VC1: DesignerTabController = DesignerTabController.alloc()
func loadImage(passedImage: UIImage){
pickedImage = passedImage
println(pickedImage) // image is accessible from here
}
override func viewDidLoad() {
super.viewDidLoad()
println(pickedImage) //image is accessible from here
VC1.pickedImageView.image = pickedImage // this line gives "unexpectedly found nil when unwrapping optional"
}
}
//this is the `UIViewcontroller` I want display the image (inside pickedImageView)
class DesignerTabController : UIViewController{
#IBOutlet weak var pickedImageView: UIImageView!
}
I realize that my way of passing the image from the UITabBarController to the sub-view will not work, even though when there are no syntax errors displayed within Xcode (it suggested pickedImageView when I started typing so I think I am really close to the solution).
If it's not possible passing data from my UITabBarController to the (first) subview, how can I pass data directly to the first subview? As I explained above, I am passing the image from another view using prepareForSegue. Does prepareForSegue directly to the first view work in my case?
Thank you very much for any suggestions, I'll try them and get back with my findings.
Your tab bar controller has viewControllers property. Just iterate through it check which controller is kind of class you need.
func passImage(passedImage: UIImage)
{
if viewControllers!.isEmpty{
return
}
for index in 0...viewControllers!.count{
if let controller = viewControllers[index] as? DesignerTabController
controller.pickedImageView.image = passedImage
}
}
solved by using viewDidLayoutSubviews() instead of viewDidLoad()
see below code for my working solution:
class DesignerTabController : UIViewController{
#IBOutlet weak var pickedImageView: UIImageView!
#IBOutlet weak var labelTest: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
}
class DesignerTabBarController : UITabBarController{
var pickedImage : UIImage = UIImage()
func loadImage(passedImage: UIImage){
pickedImage = passedImage
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidLayoutSubviews() {
if let controller = viewControllers![0] as? DesignerTabController{
controller.pickedImageView.image = pickedImage
}
}
}

Resources