I use a Menu of "code4app.net" for my app and I have a problem. Source is here : click here
I update a global var in one controller:
func sendGlobalData(){
globalCurrentUser = currentUser
}
and I use it in another:
override func viewDidLoad() {
super.viewDidLoad()
setBackButton()
self.setNavigationBarItem()
userProfilePicture.profileID = globalCurrentUser.profilePictureID
userNameLabel.text = globalCurrentUser.username
}
When I click on a menu's button I need to call again this viewDidLoad function.
How can I do that?
viewDidLoad() method its automatically called during view controller lifecycle and you should not call it manually. To update your label from other view controller you should use notification center. If you are unfamiliar with it a good starting point might be this tutorial
Related
I have 48 view controllers in my storyboard / project. I wish to have 2 different types of Navigation Bar designs.
Style 1 is a navigation bar and a status bar that is white and grey (colours not important to the question)
Style 2 is a navigation bar without a status bar. This is black.
I have set style 1 in the app delegate and set style 2 within one of the views. To a point this works and style 2 overwrites style 1. However, when I navigate away from the view, style 2 continues to override.
I could set each view controller explicitly but with 48 views and 4 or 5 lines of code to define the style is seems inefficient. If I later choose to change the style I then have 48 instances of code to edit.
My major experience is with PHP and if I had this situation I would make an include statement to reference style1 or style2 as needed.
I have tried to create a function in Swift to call the desired design but I cannot get it work as it doesn't reference the UIViewController in the same way you would when adding it directly. I have only been coding for Swift / Xcode for 3 months so it could my lack of knowledge.
I would like to find a solution that on each view I can call something like below (PseudoCode)
override func viewWillAppear(animated: Bool) {
navBarStyle1() or navBarStyle2()
}
I have not included my code to adjust the colours as I feel this is not needed for the answer.
What would be the best way to manage this efficiently? Is there an equivalent to a PHP include? If the solution is a function, could you provide an example? Or may be the solution is something different?
As requested, here is one of my view controllers:
import UIKit
class DeleteMatchViewController: UIViewController {
var idPass = ""
// OUTLETS
#IBOutlet weak var errorMessage: UILabel!
#IBOutlet weak var information: UILabel!
// ACTIONS
#IBAction func deleteMatch(sender: UIBarButtonItem) {
// connect and delete from server
// delete from core data
// load from core data
let urlParameters = "removed for privacy"
let status = sendSeverV2("\(apiUrl)/removedforprivacy.php", parameters: urlParameters)
if status == "OK"
{
// DELETESINGLE firstname|David
myDatabase("Matches", theCommand: "DELETESINGLE", theQuery: "userid|\(idPass)")
myDatabase("Messages", theCommand: "DELETEMULTIPLE", theQuery: "people|\(userId)-\(idPass)")
myDatabase("Messagesunsent", theCommand: "DELETEMULTIPLE", theQuery: "people|\(userId)-\(idPass)")
// core data
loadMatchesFromCoreData()
// segue to matches table
performSegueWithIdentifier("jumpMatches", sender: nil)
}
if status == "Error"
{
errorMessage.text = "Connection error"
}
if status == "Security"
{
errorMessage.text = "Authentication error"
authError = "yes"
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewWillAppear(animated: Bool) {
self.navigationController?.navigationBarHidden = false
self.tabBarController?.tabBar.hidden = true
errorMessage.text = ""
information.text = "If you delete this match all messages will be erased and only a future mutual match will all you to contact them again."
}
}
A little OOP can go a long way here.
First, let's make some base view controllers:
class GrayStatusBarViewController: UIViewController {
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// set up the appearance
}
}
class BlackStatusBarViewController: UIViewController {
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// set up the appearance
}
}
Now, we can make one of these for every appearance we want, and we can move any shared behavior into these base classes we want. It probably makes sense for your app to have a BaseViewController which the two classes I just posted inherit from (rather than inheriting from UIViewController directly).
Then, all you have to do is make your pile of view controllers inherit from the correct controller based on theme.
class DeleteMatchViewController: GrayStatusBarViewController {
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated) // <-- this is super important
// the rest of the view will appear code for this VC
}
}
Alternatively, you can encapsulate the appearance logic in methods in a class like I previously mentioned, the BaseViewContoller, something like this:
class BaseViewController: UIViewController {
func setUpGrayStatusBar() {
// write that logic
}
func setUpBlackStatusBar() {
// write that logic
}
// etc, as many of these as you want
}
And now, you inherit from this class and call the appropriate method:
class DeleteMatchViewController: BaseViewController {
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
setUpGrayStatusBar()
}
}
When it comes to the run time performance of your application, neither of these solutions is any different from simply copy & pasting the same code into all of your individual view controllers. Just because you didn't paste it in more than one place doesn't mean it doesn't run more than once.
I'm trying to add a UIView subview into a UIViewController, and that UIView has a UISwitch that I want the user to be able to toggle. Based on the state, a UITextField's value will toggle back and forth. Here is the subview (InitialView):
import UIKit
class InitialView: UIView {
// All UI elements.
var yourZipCodeSwitch: UISwitch = UISwitch(frame: CGRectMake(UIScreen.mainScreen().bounds.width/2 + 90, UIScreen.mainScreen().bounds.height/2-115, 0, 0))
override func didMoveToSuperview() {
self.backgroundColor = UIColor.whiteColor()
yourZipCodeSwitch.setOn(true, animated: true)
yourZipCodeSwitch.addTarget(ViewController(), action: "yourZipCodeSwitchPressed:", forControlEvents: UIControlEvents.TouchUpInside)
self.addSubview(yourZipCodeSwitch)
}
}
If I want to have it's target properly pointing at the below function, where should I either set the target or include this function? I tried:
Setting the target in the UIViewController instead of the UIView
Keeping the function in the UIView
Here's the function:
// Enable/disable "Current Location" feature for Your Location.
func yourZipCodeSwitchPressed(sender: AnyObject) {
if yourZipCodeSwitch.on
{
yourTemp = yourZipCode.text
yourZipCode.text = "Current Location"
yourZipCode.enabled = false
}
else
{
yourZipCode.text = yourTemp
yourZipCode.enabled = true
}
}
And here is where I'm loading it into the UIViewController:
// add initial view
var initView : InitialView = InitialView()
// Execute on view load
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
view.addSubview(initView)
}
Any help is much appreciated - thanks!
Yeah, the didMoveToSuperView() placement doesn't make much sense. So you're creating a random, totally unconnected ViewController instance to make the compiler happy but your project sad. Control code goes in controllers, view code goes in views.
You need in your real ViewController:
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(initView)
// Note 'self' is the UIViewController here, so we got the scoping right
initView.yourZipCodeSwitch.addTarget(self, action: "yourZipCodeSwitchPressed:", forControlEvents: .ValueChanged)
}
Also, .TouchUpInside is for UIButtons. Toggle switches are much more complicated, so their events are different. Touching up inside on a toggle switch's current setting can and should do nothing, whereas touchup inside on the opposite setting triggers the control event above. iOS does all the internal hit detection for you.
I want to update the label in the DetailViewController everytime I selected a tableRow in the MasterViewController. To achieve this, I designed a delegate, which I have in the MasterVC
protocol TestTableViewControllerDelegate {
func selectedRow(selectedCar : Car)
}
class TestTableViewController: UITableViewController {
...
var delegate : TestTableViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = DetailViewController()
The delegate works just fine, (it is implemented correctly in the DetailVC), it can pass values from TestTableVC to DetailVC and also correctly do println(), which prints a new Car.model String to the console every time I select a row in the TTVC.
The DetailVC looks like this (shortened):
class DetailViewController: UIViewController, TestTableViewControllerDelegate {
#IBOutlet var textLabel: UILabel!
var theCar : Car? {
didSet(newCar) {
refreshUI()
}
}
override func viewDidLoad() {
super.viewDidLoad()
refreshUI()
}
func selectedRow(selectedCar : Car) {
theCar = selectedCar
refreshUI()
}
func refreshUI() {
textLabel?.text = theCar!.model
}
}
I can achieve any kind of action with my delegate, expect for refreshing the UI. I have tried numerous ways, this is my latest attempt. Before that, I tried setting the textLabel's text property directly within the delegate method, didn't work. This problem only occurs when working with the UI-elements. I know it has something to do with the view not being loaded yet, but why does my refreshUI() function not work at all?
I am still a beginner, so any tip or help would be much appreciated!
A workaround I've used is to cerate a properly in the delegate and pass the value to it instead of the UI element. When the view loads I update the label's text properly with the value of the delegates property. I would think there's a better way to do this (I'm new to programming) but this is the best soultion I've come up with so far. Will update with sample code soon.
I have a BaseViewController that my UIViewControllers extend so i can have explicit functions that i dont need to rewrite. Something i would like would be a functions such as self.showSpinner() and the viewController would show the spinner
My Code looks like this
class BaseViewController: UIViewController {
var actvIndicator : UIActivityIndicatorView!
override func viewDidLoad() {
super.viewDidLoad()
self.actvIndicator = UIActivityIndicatorView(activityIndicatorStyle: .WhiteLarge)
self.actvIndicator.color = UIColor.blackColor()
self.actvIndicator.backgroundColor = UIColor.blackColor()
self.actvIndicator.frame = CGRectMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2, 100, 100);
self.actvIndicator.center = self.view.center
self.actvIndicator .startAnimating()
self.view.addSubview(self.actvIndicator)
self.actvIndicator.bringSubviewToFront(self.view)
self.edgesForExtendedLayout = UIRectEdge.None
self.navigationController?.navigationBar.translucent = false
}
func showSpinner(){
self.actvIndicator.startAnimating()
}
func hideSpinner(){
self.actvIndicator.stopAnimating()
}
}
And my viewcontrollers looks like this
class MyProjectViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.showSpinner()
}
}
MyProjectViewController have UITableView that fills the entire screen. When i set tblProjects.alpha = 0 i can see the spinner. But i want it in the front.
i also tried self.view.bringSubviewToFront(self.actvIndicator)
What am i missing?
A couple quick notes before I get into what I think your problem is:
When you add a subview it is automatically added to the top layer, no need for the bringSubviewToFront: in viewDidLoad: (which is being used wrong anyway).
You should not set view frames in viewDidLoad: (e.g. centering a view). Frames are not setup yet, so you should move that to viewWillAppear: or some other variant.
Now your issue is most likely a view hierarchy problem (further confirmed by your comment) and thus can probably be fixed by pushing the spinner to the front every time you want it to be shown, like:
func showSpinner() {
self.view.bringSubviewToFront(self.actvIndicator)
self.actvIndicator.startAnimating()
}
The problem here stands on the fact that table view is draw after you are calling self.view.bringSubviewToFront(self.actvIndicator). A possible workaround for this is to call bringSubviewToFront when showing the spinner
func showSpinner(){
self.view.bringSubviewToFront(self.actvIndicator)
self.actvIndicator.startAnimating()
}
I have been pulling my hair out trying to get this 'Delegate' thing to work in Swift for an App I am working on.
I have two files: CreateEvent.swift and ContactSelection.swift, where the former calls the latter.
CreateEvent's contents are:
class CreateEventViewController: UIViewController, ContactSelectionDelegate {
/...
var contactSelection: ContactSelectionViewController = ContactSelectionViewController()
override func viewDidLoad() {
super.viewDidLoad()
/...
contactSelection.delegate = self
}
func updateInvitedUsers() {
println("this finally worked")
}
func inviteButton(sender: AnyObject){
invitedLabel.text = "Invite"
invitedLabel.hidden = false
toContactSelection()
}
/...
func toContactSelection() {
let contactSelection = self.storyboard?.instantiateViewControllerWithIdentifier("ContactSelectionViewController") as ContactSelectionViewController
contactSelection.delegate = self
self.navigationController?.pushViewController(contactSelection, animated: true)
}
ContactSelection's contents are:
protocol ContactSelectionDelegate {
func updateInvitedUsers()
}
class ContactSelectionViewController: UITableViewController {
var delegate: ContactSelectionDelegate?
override func viewDidLoad() {
super.viewDidLoad()
self.delegate?.updateInvitedUsers()
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// Stuff
self.delegate?.updateInvitedUsers()
}
}
What am I doing wrong? I am still new and don't fully understand this subject but after scouring the Internet I can't seem to find an answer. I use the Back button available in the Navigation Bar to return to my CreateEvent view.
var contactSelection: ContactSelectionViewController = ContactSelectionViewController()
This is instantiating a view controller directly, and the value never gets used. Since it looks like you're using storyboards, this isn't a good idea since none of the outlets will be connected and you'll get optional unwrapping crashes. You set the delegate of this view controller but that's irrelevant as it doesn't get used.
It also isn't a good idea because if you do multiple pushes you'll be reusing the same view controller and this will eventually lead to bugs as you'll have leftover state from previous uses which might give you unexpected outcomes. It's better to create a new view controller to push each time.
In your code you're making a brand new contactSelection from the storyboard and pushing it without setting the delegate.
You need to set the delegate on the instance that you're pushing onto the navigation stack.
It's also helpful to pass back a reference in the delegate method which can be used to extract values, rather than relying on a separate reference in the var like you're doing.
So, I'd do the following:
Remove the var contactSelection
Add the delegate before pushing the new contactSelection object
Change the delegate method signature to this:
protocol ContactSelectionDelegate {
func updateInvitedUsers(contactSelection:ContactSelectionViewController)
}
Change your delegate calls to this:
self.delegate?.updateInvitedUsers(self)