Where to store constant values in swift? - ios

I'm trying to build my first spritekit game in swift. I don't understand where to store constants so I can make them available to the whole project. I have some experience with C++ and I used to create a Constants.h file. Is there such thing in Swift? What's the recommended practice to do this?
Right now I'm using a struct with static constants but I'm not sure if it's the right way to do it:
struct Constants {
static let gravity : Int = 20
}

struct Constants {
static let buildName = "Orange-Pie"
struct FacebookConstants {
static let clientId ="asdasdsa"
}
struct TwitterConstants {
static let clientId ="asdasdsa"
}
}
Use :
Constants.FacebookConstants.clientId

If you have highly generic constants needed by every part of your program, this is indicating a design problem (whenever you are at a loss of where something should go, you probably have a design problem). Things like a gravitational constant shouldn't be necessary for the vast majority of the program, so they generally don't need to be global constants (that's true in C++, too).
Put your constants with the thing that needs that constant, or pass them into the thing that needs that constant. SpriteKit should do most gravity calculations for you, but if you're doing additional physics work, then there should be some object that represents the physics engine or "the world." That's where the gravity constant belongs. Alternately, put the gravity constant into a struct that you pass into the physics engine at launch.
Even if you do have very broad need of the gravitational constant, then you should put it into a struct like PhysicalConstants, not a generic Constants (which makes code reuse hard because it mixes unrelated things). A common case of this in my code are "style" constants like "the systemwide highlight color" (which are likely to be changed by the client, so I want a single place to modify them). These go into a header called Style.h in my apps, and now would go into a Style struct. But they're kept separate from non-style constants.

When I was at WWDC 2014, I asked an engineer the exact same thing. Their recommendation was to use your method to replace #define that we had in Objective-C. I agree that it's a suboptimal procedure and actual defining should be implemented in some way.
Also note that I don't think you need to explicitly state the type of your variable, as Swift has rather advanced type inference. So this should work:
struct Constants {
static let gravity = 20
}

struct Constants {
static let varName = "AnyValue"
}
Accessing to varName:
Constants.varName

Related

Static variables vs methods to store properties

In my SwiftUI application I'm currently using a global struct that holds constants properties like colors or sizes.
E.g.
struct App {
struct Colors {
static let mainAppColor: UIColor = UIColor(red: 233/255, green: 230/255, blue: 231/255)
static let mainWhiteColorMiddleOpacity: UIColor = UIColor.white.opacity(0.5)
}
}
// usage
struct ContentView: View {
var body: some View {
Rectangle().foregroundColor(App.Colors.mainBlueColor)
}
}
I was debating whether this is a bad practice since I have LOTS of static variables, and was wondering if replacing them with static methods or computed properties would decrease memory usage (since body gets computed lots of times). E.g. replacement:
struct App {
struct Colors {
static var mainBlueColor: UIColor { UIColor.blue }
static var mainWhiteColorMiddleOpacity: UIColor { UIColor.white.opacity(0.5) }
}
}
// usage
struct ContentView: View {
var body: some View {
Rectangle().foregroundColor(App.Colors.mainBlueColor)
}
}
One would increase heap usage and the other stack usage, right?
What do you think would be the best practice?
Premature (and ill-conceived) optimization. You probably have no idea how little memory is actually taken up by even thousands of these values, in the grand scheme of things; it's trivial. And any decently written app will have a lot of them; it's what you do.
A struct is a great way to organize and namespace these sorts of things, although it happens that an enum is now Apple's preferred way (for reasons that I do not entirely understand).
Your "since body gets computed lots of times" is totally irrelevant: the name is a direct reference to the value with absolutely no overhead, since if you use let the whole thing is compiled away and replaced by the value right at the point of reference in your code. Lookup time at runtime is zero!
(A computed value or method, on the other hand, might require some serious overhead to run each time, potentially bringing the entire message dispatch mechanism into play, though it might in fact be inlined away perhaps. Serious backsliding there.)
Computed properties are only useful if there is something to compute so the variable makes sense.
You are definitely creating constants (as you mentioned), so use let
Regarding memory usage: How about declaring colors in the assets catalog?
I would say never use Computed properties for the things you already knows the answer or value, from the other side do you know how many times would SwiftUI run that Computed properties for using it? so many run code for getting the same thing!
you can use Computed properties for the things you need once or some times in your app just for reading value, for example you have a Rectangle that you know the width and height, then use Computed properties for getting the area, or something related like that, after reading value you would be finished with that as well, and there is no need to store it as well.

Refactoring large Swift struct with mutating functions

I'm trying to simplify a huge file in Swift and I'm not sure what would be the best approach. It might be a very naive question as I'm still fairly new to Swift :)
For the sake of simplicity, let's say I have one User struct and in it I can call a ton of different setupModeA, setupModeB and so on, called depending on various conditions:
struct User {
var currentMode: String
mutating func setupModeA() {
currentMode = "A"
}
mutating func setupModeB() {
currentMode = "B"
}
// and so on for each mode
}
I'd like to be able to take the setupMode*() functions and their associated helper functions into a separate file to make it easier to read through, since most of the time I'd be focusing on only one mode.
I was thinking:
struct ModeA {
mutating func setup() {
// change the mode from there
}
}
However I can't figure out how to simply pass and mutate the User info to this new struct.
I thought about:
initializing a bunch of ModeX objects with a user variable in the User struct and passing the User on init, but it creates weird behaviours.
using static methods on the ModeX structs, but then I'm not quite sure how to mutate the User
taking a more functional approach & not mutating the User but instead cloning it and re-assigning it each time... this would probably work but since my code is very sequencial it feels like added complexity / memory usage for nothing.
switching from struct to classes and hoping it gives me other options... but I'm afraid everything would break
really complex things that feel too weird and unintuitive to be mentioned here :)
Any pointers would be much appreciated.

Swift: To struct, or not to struct

I'm finally making the switch from Objective-C to Swift. I'm creating a view layout system for my client to make their apps more flexible in layout, without using auto layout as they want to design their screens remotely and auto-layout would be too complex for them. I tried to do this using structs and protocols but I found it to be quite clumsy, so I'm suspecting I'm not thinking about it the right way.
With classes, the structure would be as follows:
class ViewModel {
var frame: CGRect = .zero
}
class ViewGroupModel: ViewModel {
var weight: Int = 1
var children:[ViewModel] = [ViewModel]()
}
class HorizontalViewGroupModel: ViewGroupModel {
}
class VerticalViewGroupModel: ViewGroupModel {
}
I tried to approach it with protocols by defining a ViewModel protocol, and a ViewGroupModel protocol, but I found it created a lot of duplication (properties). Is there a better approach? Would it be considered a good practice to use classes in this case?
EDIT: In case it would be better to not uses classes, I am looking for an answer that gives me a concrete solution in terms of structs and protocols.
If the concern was merely how to implement the protocol's properties, I wouldn't necessarily let that sway my choice between struct vs class. If you had a variety of properties that your struct types must implement, you have two basic options:
If you're talking about a few properties, just implement those few properties in your struct types that conform to that protocol. We do this all the time. E.g. when defining custom types that conform to MKAnnotation, we simply implement the three required properties.
Sure, if we're talking about a much larger set of properties, this gets tedious, but the compiler holds our hand through this process, ensuring that we don't miss anything. So the challenge is fairly modest.
While I'm not a fan of this approach, https://stackoverflow.com/a/38885813/1271826 shows that you could implement the shared properties as a component, where you have struct to wrap all of these properties, and then implement default computed properties for your protocol in an extension:
enum SubviewArrangement {
case none
case horizontal
case vertical
case flow
}
struct ViewComponent {
var frame = CGRect.zero
var weight = 1
var subviews = [ViewModel]()
var subviewArrangement = SubviewArrangement.none
}
protocol HasViewComponent {
var viewComponent: ViewComponent { get set }
}
protocol ViewModel: HasViewComponent { }
extension ViewModel {
var frame: CGRect {
get { return viewComponent.frame }
set { viewComponent.frame = newValue }
}
var weight: Int {
get { return viewComponent.weight }
set { viewComponent.weight = newValue }
}
var subviews: [ViewModel] {
get { return viewComponent.subviews }
set { viewComponent.subviews = newValue }
}
var subviewArrangement: SubviewArrangement {
get { return viewComponent.subviewArrangement }
set { viewComponent.subviewArrangement = newValue }
}
}
Where, you can then create an instance that conforms to ViewModel, like so:
struct LabelModel: ViewModel {
var viewComponent = ViewComponent()
}
var label = LabelModel()
label.weight = 2
print(label.weight)
I have to confess, this isn't the most elegant approach. (I hesitate to even present it.) But it avoids having to implement all of those properties individually in your types that conform to ViewModel.
So, let's set the property question aside. The real question is whether you should be using value type (struct) or reference type (class). I think it's illuminating to consider Apple's discussion of value vs reference semantics near the end (#42:15) the Protocol-Oriented Programming in Swift video. They touch upon those cases where you actually may still want to use classes. For example, they suggest you might want to use reference types when, "Copying or comparing instances doesn't make sense". They suggest this rule might apply when dealing with "Window" instances. The same applies here.
On top of that, it doesn't seem to me that there is much benefit to use value types to represent a view hierarchy, which is a collection of reference type objects. It only makes it more confusing. I would just stick with class types, as it will accurately mirror the view hierarchy it represents.
Don't get me wrong: We're so used to using reference types that I think it's always good to challenge our preconceived notions and take a long hard look at whether a value type could better address the situation. In this case, though, I simply wouldn't worry about it and just stick with a class hierarchy that mirrors the hierarchy of those objects you're modeling.
That having been said, the class hierarchy proposed in your question doesn't quite feel right, either. It feels strange that you can actually instantiate a ViewModel to which you can't later add subviews (whereas all UIView objects have subview property). Also, your horizontal and vertical group types don't feel correct either. For example, should it be a single type with some "axis" property, like UIStackView or some other "arrangement" property, to broaden the notion to capture UICollectionView layouts, too?. As you'll see in my ViewComponent example, above, I've flattened this a bit, with these two caveats in mind, but do whatever you see fit.
In general, use a class only if you need the special features of classes, which are:
A class can have a superclass and/or a subclass; a struct can't.
A class is a reference type, while a struct is a value type.
Objective-C can introspect a class (esp. if it derives from NSObject), whereas it cannot even see a struct declared in Swift.
Its always good to code to interface/protocol than to classes/structs. This your model wisely.
You can make use of generics as well beautifully for this purpose. I hope it would save a lot of variables and duplications for you.
For layout purpose in my opinion structs coupled with protocols and generics would make a great design. I don't see for you any need to use classes in your case.
Its always good to know in and out of a feature to better use it. The main difference between structs and classes in Swift are
Class objects are stored/passed as references where as struct instances are stored/passed as values
Reference counting allows more than one reference to a class instance.
For Class we have identity operators === and !== which are used to check whether two variables or constants refer to the same instance of Class. The question for identity operators does not arise for Struct because two different Struct variables or constants can not point to same instance. You can try applying identity operator to Struct types. You will get compile time error.
Inheritance enables one class to inherit the characteristics of another.
Type casting enables you to check and interpret the type of a class instance at runtime.
Deinitializers enable an instance of a class to free up any resources it has assigned.
For detailed disscussion you can through my post Struct Vs Classes in Swift.

What should I do about frequently repeated constants?

This seems like a very simple question, but I can't find a clear answer. Also it's not specifically about swift or iOs, but I'm new to programming and swift is the only language I know anything about, so I don't know how to phrase it for a more general context.
I'm trying to write an iOs app and I found myself defining the same constants many times throughout my code.
I must have written this line about a hundred times, for instance:
let calendar = NSCalendar.currentCalendar()
Another example is getting my only User object from its persistent store:
let realm = try! Realm()
let user = realm.objects(User).first!
I define those calendar and user constants over and over throughout my whole code in classes and subclasses and extensions and computed properties.
That seems kind of stupid, though. I think I should be able to define calendar once and for all and just use it when I need it. So my first thought was to declare a global constant, but apparently everybody thinks anything with the word "global" in it should be avoided at all costs.
So what should I do? Is there another solution for this? Should I just keep writing the same stuff over and over again?
Thanks in advance,
Daniel
There are many different situations in which the best use of different approaches.
For example in your case:
let calendar = NSCalendar.currentCalendar()
currentCalendar is a static method that already returns a pointer to the object that you will use. And you don't need to set it to some constant for using with simple case:
print(NSCalendar.currentCalendar().calendarIdentifier)
Another thing that is most often better to use a shorter name for the object in your code when you need to refer to it often and this code looks much more readable:
print(calendar.calendarIdentifier)
If you have the functionality that you will often use in application from different places, you can just make it to the static method and does not create an object of this class every time you call it:
class NetworkConnection {
class func getDataFromServet(completion block: (data: SomeType) -> Void) {
...
}
}
And use it without object creation like:
NetworkConnection.getDataFromServer(completion: {(data: SomeType) -> Void in
...
})
If you need to use created object in many places, the best solution is not to make it global or singleton instance, but pass a pointer to it to the objects where you need to use it. This makes the code more readable, for example by looking at the input parameters of the init method, anyone can immediately understand which objects use this class for their work. And this class is easier to take from the project in a separate module and connect to another project. At that time, if you use the singleton instance, the class's interface is not clear what it can be used and this leads to code obfuscation. This applies and to the global objects.
If you're constantly changing it, why aren't you just using var instead of let?

Move from old-fashioned struct to class

I know this could be a noob question but I am a bit stucked here. I usualy makes the following to access app data in different ViewControllers: First I declare a global.h module like this
global.h
typedef struct {
NSString *appName
NSString *appVersion;
bool mode;
} structApp;
extern structApp app;
After that I declare in MainViewController.h the struct so that I can access data
#implementation ViewController
structApp app;
- (void)viewDidLoad
{
app.appVersion = #"v1.02";
}
#end
And then I include "global.h" in every ViewController.h
This way I can access globally. As far I can see this is a good implementation and I have used it in more than 20 apps. Problem starts when this struct grows in size. In those cases I see corrupted memory, nil variables that were previously loaded with data, etc.
There is a better way of making data available in all ViewController? Please give me some examples if you can.
You have two options
Use a singleton class - Refer Objective C Singleton
Declare properties in App delegate - Refer SO
You can access the app delegate from any class using:
AppDelegate *appDel = [[UIApplication sharedApplication] delegate];
As you were using extern in your structure, any object updating the same value.
In OOPS, global variables are never said Good, so you need to use a singleton pattern.
Create a singleton/shared class having all those stuffs in your structure and use it.
You should deal with struct only if you deal with primitive data (if you are in a OOP way).
app.appVersion = #"v1.02";
Make your struct pointing on dangling pointer, since you are pointing a data in a function scope (app.appVersion is only holding the pointer, not the data). So you must retain all those object values in order to make it content safe, but i must admit it is still a Q&D approach.
If you need global access to data, you can use a singleton, only if you really need strong encapsulation and control to data.
How to make a singleton
What should my Objective-C singleton look like?
You can use macro too, that way you'll can use constants string without worrying data persistency, since they will always be available into the scope you are dealing with.
If you only want to read the data and you dont need any complex data structure you can also use a settings file like
Settings.h
#define appName #"blabla"
#define appVersion #"1.01"
#define mode 1
In General using struct should work fine. There is nothing wrong with using them. If you observe weird values caused by overlapping memory or illegal re-use of it or so then your problem is somewhere else but not in using structs in principle. The extern statement could lead to such an issue.
A class is not much more than a struct too, from a memory usage perspective. If I were you I would design a class with properties where ever you have members when using a struct. And make use of them in pretty the same way.
For "global variables" I apply a singleton pattern. That is basically a class with a class method (the leading + instead of -) that makes the one and only instance of the class available. Within that method I check if the class (a class internal static reference to the same class) is already available (!= nil) and instantiate it. Sometimes I use the initialize method for that. Initialize is an objective-c typical thing. It is called only once for each class, even subclassed ones, when or before the class is used for the first time. A very good place for instantiating class variables as singletons but not portable to other programming languages.

Resources