I recently watched a video tutorial in Lynda.com and I noticed that the author declared a few global variables which included two class instances. The main reason for my question is because I have heard that we need to try to avoid using global variables unless your really need them. I can see using global variables for NSUserDefaults' Keys but I'm not sure about global instances.
Here is the code showing the global variables declarations. I'm only concerned about variables masterView and detailViewController.
import UIKit
var objects:[String] = [String]()
var currentIndex:Int = 0
var masterView:MasterViewController?
var detailViewController:DetailViewController?
let kNotes:String = "notes"
let BLANK_NOTE:String = "(New Note)"
class MasterViewController: UITableViewController {
// class code
}
Is it ok to declare your class instances as global variables?
It is certainly OK to use global variables in your Swift code from the technical point of view, in the sense that your program is not going to crash or otherwise "misbehave" because of that. When you are building a quick example for a demonstration, global variables provide a convenient way to shorten the code.
However, there are drawbacks to using mutable global variables that makes their use questionable. Specifically, they break encapsulation. Looking at the code that you provided, two variables
var objects:[String] = [String]()
var currentIndex:Int = 0
should be hidden in a model object, over which you have some degree of control.
Using globals may produce some unexpected behavior if you are not careful about clearing them. For example
var masterView:MasterViewController?
var detailViewController:DetailViewController?
may retain references to view controllers that are no longer visible.
That's okay to declare a class instances as a global variable, if you want to prefer use of only one instance of that class through out your app work.
NOTE: you can hide those properties & functions of that instance by making those Private, which you don't want to be accessed by global instance variable.
Related
I am new to Swift, coming from C and Java background.
I am trying to pass a struct (called 'Player') object from one view controller to another, and as i learned one proper way to do is first defining it in the target VC like:
class TargetVC: UIViewController {
var playerVar: Player!
}
And then assigning it in prepare function inside source VC:
if let targetVC = segue.destination as? TargetVC
{
targetVC.playerVar = myPlayer
}
But i thinked about simply using a global variable to pass the Player object to the target view controller by defining it like:
var myPlayer = Player() // Global Variable
class SourceVC: UIViewController {
}
Then reaching it in target VC:
class TargetVC: UIViewController {
myPlayer.name = // Stuff
}
Would this method cause any problems in runtime or does it have any disadvantages? If yes, what are them?
Thanks in advance.
Passing data gives to you to conform programming principles to build a good classes, even in your example. It makes classes more extendable and reusable in many cases.
Global var gives some advantages to reach needed data, but you have to care about reference cycles, memory managing, handle threads, queues and blocks, etc.
You can also read out about singletones, static vars,... – where you can get some data from class scope vars.
One disadvantage is, as the name suggests, everything has access to global variables, even things that have no reason to see, much less modify, that data.
I am programming a board game. There are a couple of screen and many functions. I often need to change some variable like "money" or "wood".
I added "didset" so I can update a View that displays the amount of money.
I see two options for this. Either a global variable
var money = 0 {didSet {NotificationCenter.default.post(name: NSNotification.Name(rawValue: "showMoney"), object: nil)}}
or a singleton
class resources {
static let shared = resources()
var money = 0 {didSet {NotificationCenter.default.post(name: NSNotification.Name(rawValue: "ResourcenAnzeigen"), object: nil)}}
private init() {}
}
Now I read singletons are always preferred instead of globals. But I wonder why. In my example both seem to do the same. The only difference is I either have to write
money += 1
or
resources.shared.money += 1
The first one looks easier.
And is there a third better way? I read one could give over the needed variables to every function or viewcontroller - but that looks to me like much unneccessary extra code?
Actually a Singleton is a special case of a global variable.
Accessing the global Singleton instance is just shadowed.
This helps to keep the global namespace cleaner.
But a Singleton SHOULD NOT be used for global accesses.
In iOS Singletons are used for unique resources like file system, network, user data, etc.
I suggest you to create an instance at the root of your application and inject this where you need it.
This makes also testing easier and keeps your code clean.
There you can also use the observer pattern to avoid the global NotificationCenter.
FYI: Communication Patterns
Singleton would be the right way to do.
The main problem with using a global variable instead of a singleton for these purposes would be that in case you have a local variable money in some other entity, the compiler would not be implicitly able to identify which money you were referring to.
So, in case you decide to add money as a variable at some other location, and you try to update this global money variable inside the same, it would end up modifying your local variable, and would not update your global one.
But, when you are using a singleton to set or get such a property, you would be safe from this situation.
var money = 0
class MyClass {
var money = 0
func doSomethingAndIncrementGlobalMoney() {
money += 1
}
}
print(money) // Prints 0
let myObject = MyClass()
myObject.doSomethingAndIncrementGlobalMoney()
print(money) // Prints 0, while the expectation was to increment the global 'money' by 1.
Or, you could just go with using something like:
struct MyGlobalItems {
static var money: Int = 0
}
// Using the variable:
MyGlobalItems.money += 1
What is the difference between global variable and shared instance in Swift? what are their respective field of use? Could anyone clarify their concept based upon Swift.
A global variable is a variable that is declared at the top level in a file. So if we had a class called Bar, you could store a reference to an instance of Bar in a global variable like this:
var bar = Bar()
You would then be able to access the instance from anywhere, like this:
bar
bar.foo()
A shared instance, or singleton, looks like this:
class Bar {
static var shared = Bar()
private init() {}
func foo() {}
}
Then you can access the shared instance, still from anywhere in the module, like this:
Bar.shared
Bar.shared.foo()
However, one of the most important differences between the two (apart from the fact that global variables are just generally discouraged) is that the singleton pattern restricts you from creating other instances of Bar. In the first example, you could just create more global variables:
var bar2 = Bar()
var bar3 = Bar()
However, using a singleton (shared instance), the initialiser is private, so trying to do this...
var baaar = Bar()
...results in this:
'Bar' initializer is inaccessible due to 'private' protection level
That's a good thing, because the point of a singleton is that there is a single shared instance. Now the only way you can access an instance of Bar is through Bar.shared. It's important to remember to add the private init() in the class, and not add any other initialisers, though, or that won't any longer be enforced.
If you want more information about this, there's a great article by KrakenDev here.
Singleton (sharing instance)
Ensure that only one instance of a singleton object is created & It's provide a globally accessible through shared instance of an object that could be shared even across an app.
The dispatch_once function, which executes a block once and only once for the lifetime of an app.
Global variable
Apple documentation says Global variables are variables that are defined outside of any function, method, closure, or type context.
I've made a small class to test when object declaration occurs.
class MyObject
{
static let instance = MyObject();
required init()
{
println("init")
}
}
And when I run this, "init" is only printed when I reference MyObject.instance, meaning that static variables are declared lazily.
The reason I need this to be eager is because
I want to keep a lookup table of object instances for myself (with weak references, don't worry). Instances to be inserted during their init and expose a lookup function, so the functionality is encapsulated.
I'd prefer if I didn't need a separate function at App start to make references to static variables to achieve this.
I am not aware of an eager keyword, but is there an accepted solution to this? Will it be added in Xcode 7?
I been reading about avoiding the mutable state, and how the singleton pattern is bad for having a global state.
I see few answers about Dependency injection http://www.objc.io/issue-13/singletons.html, but I can not find how to solve this basic approach:
How maintain the user data arround the app?, the solution is to pass the user information from the one view (where is requested by webservice) through the views by parameter to the seven push view (where is needed again) ?
there is a better way?, or the singleton pattern is sometimes necessary?
I use a singleton to represent my Engine class in Swift. It is initialized once on launch and contains static class variables stored in a struct. Works fine for me.
class Engine{
struct properties{
static var resourceManager:ResourceManager!;
...
}
init(){
properties.resourceManager = ResourceManager();
}
In another class I can then call
Engine.properties.resourceManager