Should I make my own getters and setters in Swift? Im confused by the built in getters ad setters...is this even needed?
//properties for the resident
private var name: String!
var apartmentNumber: String!
var email : String!
var phoneNumber : String!
public func getName()->String{
return self.name
}
public func setName(name : String){
self.name = name
}
}
I've written an article for exactly this. I'll paste it here.
Stop writing getters and setters in Swift
I see this time and time again, and it's about time I write an article in one place to consolidate all my thoughts. If you find yourself writing code that looks like this, listen up:
public class C {
private var _i: Int = 0
public var i: Int {
get {
return self._i
}
set {
self._i = newValue
}
}
}
This pattern* is completely pointless in Swift, and I'll explain why, but firstly we need to take a short detour through Java land. Why Java? Because most of the people I run into who write Swift like this have some sort of Java background, either
because it was taught in their computer sceince courses, or
because they're coming over to iOS development, from Android
What's the point of getters and setters?
Suppose we have the following class in Java:
public class WeatherReport {
public String cityName;
public double temperatureF;
public WeatherReport(String cityName, double temperatureF) {
this.cityName = cityName;
this.temperatureF = temperatureF;
}
}
If you showed this class to any CS prof, they're surely going to bark at you for breaking encapsulation. But what does that really mean? Well, imagine how a class like this would be used. Someone would write some code that looks something like this:
WeatherReport weatherReport = weatherAPI.fetchWeatherReport();
weatherDisplayUI.updateTemperatureF(weatherReport.temperatureF);
Now suppose you wanted to upgrade your class to store data in a more sensible temperature unit (beating the imperial system dead horse, am I funny yet?) like Celcius or Kelvin. What happens when you update your class to look like this:
public class WeatherReport {
public String cityName;
public double temperatureC;
public WeatherReport(String cityName, double temperatureC) {
this.cityName = cityName;
this.temperatureC = temperatureC;
}
}
You've changed the implementation details of your WeatherReport class, but you've also made an API breaking change. Because temperatureF was public, it was part of this class' API. Now that you've removed it, you're going to cause compilation errors in every consumer that depended on the exitense of the temperatureF instance variable.
Even worse, you've changed the semantics of the second double argument of your constructor, which won't cause compilation errors, but behavioural errors at runtime (as people's old Farenheit based values are attemped to be used as if they were celcius values). However, that's not an issue I'll be discussing in this article.
The issue here is that consumers of this class will be strongly coupled to the implementation details of your class. To fix this, you introduce a layer of seperation between your implementation details and your interface. Suppose the Farenheit version of our class was implemented like so:
public class WeatherReport {
private String cityName;
private double temperatureF;
public WeatherReport(String cityName, double temperatureF) {
this.cityName = cityName;
this.temperatureF = temperatureF;
}
public String getCityName() {
return this.cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
public double getTemperatureF() {
return this.temperatureF;
}
public void setTemperatureF(double temperatureF) {
this.temperatureF = temperatureF;
}
}
The getters and setters are really basic methods that access or update our instance variables. Notice how this time, our instance variables are private, and only our getters and setters are public. A consumer would use this code, as so:
WeatherReport weatherReport = weatherAPI.fetchWeatherReport();
weatherDisplayUI.updateTemperatureF(weatherReport.getTemperatureF());
This time, when we make the upgrade to celcius, we have the freedom to change our instance variables, and tweak our class to keep it backwards compatible:
public class WeatherReport {
private String cityName;
private double temperatureC;
public WeatherReport(String cityName, double getTemperatureC) {
this.cityName = cityName;
this.temperatureC = temperatureC;
}
public String getCityName() {
return this.cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
// Updated getTemperatureF is no longer a simple getter, but instead a function that derives
// its Farenheit value from the Celcius value that actuallyed stored in an instance variable.
public double getTemperatureF() {
return this.getTemperatureC() * 9.0/5.0 + 32.0;
}
// Updated getTemperatureF is no longer a simple setter, but instead a function
// that updates the celcius value stored in the instance variable by first converting from Farenheit
public void setTemperatureF(double temperatureF) {
this.setTemperatureC((temperatureF - 32.0) * 5.0/9.0);
}
// Mew getter, for the new temperatureC instance variable
public double getTemperatureC() {
return this.temperatureC;
}
// New setter, for the new temperatureC instance variable
public void setTemperatureC(double temperatureC) {
this.temperatureC = temperatureC;
}
}
We've added new getters and setters so that new consumers can deal with temperatures in Celcius. But importantly, we've re-implemented the methods that used to be getters and setters for temperatureF (which no longer exists), to do the appropraite conversions and forward on to the Celcius getters and setters. Because these methods still exist, and behave identically as before, we've successfully made out implementation change (storing F to storing C), without breaking our API. Consumers of this API won't notice a difference.
So why doesn't this translate into Swift?
It does. But simply put, it's already done for you. You see, stored properties in Swift are not instance variables. In fact, Swift does not provide a way for you to create or directly access instance variables.
To understand this, we need to have a fuller understanding of what properties are. There are two types, stored and computed, and neither of them are "instance variables".
Stored properties: Are a combination of a comiler-synthesized instance variable (which you never get to see, hear, touch, taste, or smell), and the getter and setter that you use to interact with them.
Computed proepties: Are just a getter and setter, without any instance variable to act as backing storage. Really, they just behave as functions with type () -> T, and (T) -> Void, but have a pleasant dot notation syntax:
print(weatherReport.temperatureC)
weatherReport.temperatureC = 100
rather than a function calling synax:
print(weatherReport.getTemperatureC())
weatherReport.setTemperatureC(100)
So in fact, when you write:
class C {
var i: Int
}
i is the name of the getter and setter for an instance variable the compiler created for you. Let's call the instance variable $i (which is not an otherwise legal Swift identifier). There is no way to directly access $i. You can only get its value by calling the getter i, or update its value by calling its setter i.
So lets see how the WeatherReport migration problem looks like in Swift. Our initial type would look like this:
public struct WeatherReport {
public let cityName: String
public let temperatureF: Double
}
Consumers would access the temperature with weatherReport.temperatureF. Now, this looks like a direct access of an isntance variable, but remember, that's simply not possible in Swift. Instead, this code calls the compiler-syntehsized getter temperatureF, which is what accesses the instance variable $temperatureF.
Now let's do our upgrade to Celcius. We will first update our stored property:
public struct WeatherReport {
public let cityName: String
public let temperatureC: Double
}
This has broken our API. New consumers can use temperatureC, but old consumers who depended on temperatureF will no longer work. To support them, we simply add in a new computed property, that does the conversions between Celcius and Fahenheit:
public struct WeatherReport {
public let cityName: String
public let temperatureC: Double
public var temperatureF: Double {
get { return temperatureC * 9/5 + 32 }
set { temperatureC = (newValue - 32) * 5/9 }
}
}
Because our WeatherReport type still has a getter called temperatureF, consumers will behave just as before. They can't tell whether a property that they access is a getter for a stored property, or a computed property that derives its value in some other way.
So lets look at the original "bad" code. What's so bad about it?
public class C {
private var _i: Int = 0
public var i: Int {
get {
return self._i
}
set {
self._i = newValue
}
}
}
When you call c.i, the following happens:
You access the getter i.
The getter i accesses self._i, which is yet another getter
The getter _i access the "hidden" instance variable $i
And it's similar for the setter. You have two layers of "getterness". See what that would look like in Java:
public class C {
private int i;
public C(int i) {
this.i = i;
}
public int getI1() {
return this.i;
}
public void setI1(int i) {
this.i = i;
}
public int getI2() {
return this.getI1();
}
public void setI2(int i) {
this.setI1(i);
}
}
It's silly!
But what if I want a private setter?
Rather than writing this:
public class C {
private var _i: Int = 0
public var i: Int {
get {
return self._i
}
}
}
You can use this nifty syntax, to specify a seperate access level for the setter:
public class C {
public private(set) var i: Int = 0
}
Now isn't that clean?
There is no need to create setters and getters for stored properties in Swift and you shouldn't create them either.
You can control the accessibility of getters/setters separately when you declare a property.
public private(set) var name: String // public getter, private setter
If you want to implement some custom logic in your setter, you should use property observer, i.e. didSet/willSet.
var name: String {
didSet {
// This is called every time `name` is set, so you can do your custom logic here
}
}
You will hardly come across the need to create your own getters and setters.
Swift's computed property lets you use getters and setters in a very simple way.
Eg: below defined is a computed property circleArea that returns area of circle depending on radius.
var radius: Float = 10
var circleArea: Float {
get {
return .pi * powf(radius, 2)
}
set {
radius = sqrtf(newValue / .pi)
}
}
While you can observe a stored value and perform some task using property observers:
var radius: Float = 10 {
willSet {
print("before setting the value: \(value)")
}
didSet {
print("after the value is set: \(value)")
}
}
radius += 1
// before setting the value: 10.0
// after the value is set: 11.0
However if you feel like using getter setter, you can define appropriate functions for that. Below defined is an extension on Integer to get and set properties value.
extension Int {
func getValue() -> Int {
return self
}
mutating func setValue(_ val: Int) {
self = val
}
}
var aInt: Int = 29
aInt.getValue()
aInt.setValue(45)
print(aInt)
// aInt = 45
Consider a protocol that have a factory method:
public protocol Frobnicator {
func frobnicate()
static func makeRightFrobnicator() -> Frobnicator
}
private class SomeFrobnicatorImplementation: Frobnicator { ... }
private class AnotherFrobnicatorImplementation: Frobnicator { ... }
public extension Frobnicator {
static func makeRightFrobnicator() -> Frobnicator {
if something {
return SomeFrobnicatorImplementation()
} else {
return AnotherFrobnicatorImplementation()
}
}
}
I want to be able to construct different implementors at different times. The implementors themselves are private to the module, whereas the protocol is public to use in the client code.
When I try the code similar to that above, I get “Static member makeRightFrobnicator cannot be used on protocol metatype Frobnicator.Protocol.”
Is there any way around it, or should I just use a free function?
The static function implementation is legal:
protocol P {
static func f() -> P
init()
}
extension P {
static func f() -> P {return self.init()}
}
But you'll notice that in order to get it to compile, I had to guarantee to the compiler that I have in hand a legal way to make a P so as to able to return one.
The issue in your code is the attempt to return a specific adopter of your protocol, like a SomeFrobnicatorImplementation. A protocol is agnostic as to who adopts it. To put it another way, you cannot guarantee within the protocol definition that SomeFrobnicatorImplementation will in fact be an adopter of this protocol. Thus, that part of your code is illegal.
I need to create objects from string names that I am reading from a script. I don't want to use the Objective-C runtime.
In my C++ implementation, each class registered itself with an object factory singleton through a global static variable. When the dll loads, the globals were initialized, and all available classes were registered.
I don't want the object factory to have hard coded pre-knowledge of all possible types.
In Swift, all globals are lazily initialized so my C++ registration strategy doesn't work.
Is there some init API that swift calls once per module load?
If not, does anyone have a good idea for class registration?
public enum DynamicTypeFactoryError : ErrorType {
case ClassNotRegistered
}
public protocol DynamicType {
static var dynamicClassName: String { get }
init()
}
public struct DynamicTypeRegistraion<T: DynamicType> {
public init() {
DynamicTypeFactory.inst.register(T.dynamicClassName, factory: { T() })
}
}
//===========================================================================
// singleton
public class DynamicTypeFactory {
// properties
public static let inst = DynamicTypeFactory()
typealias ClassFactoryType = (Void) -> DynamicType
var registry = [String : ClassFactoryType]()
// methods
public func create(className: String) throws -> DynamicType {
// make sure the class exists
guard let factory = registry[className] else {
throw DynamicTypeFactoryError.ClassNotRegistered
}
return factory()
}
/// This is used to register an object so it can be dynamically created
/// from a string.
public func register(className: String, factory: (Void) -> DynamicType) {
if (registry[className]) != nil {
// TODO - this should be logged
assertionFailure("Class: \(className) is already registered")
} else {
registry[className] = factory
}
}
}
//===========================================================================
// MyObject
public struct MyObject : DynamicType {
// properties
static let registration = DynamicTypeRegistraion<MyObject>()
public static var dynamicClassName = "MyObject"
public init() {
}
}
// Usage
let myObj = try? DynamicTypeFactory.inst.create("MyObject")
Since MyObject's static registration is not initialized, calling create fails because it hasn't been registered yet.
After reviewing the links posted by Martin R, it appears there is no "non-lazy" initialization of statics, and this is by design. So a different approach will be needed for Swift applications. Thanks Martin!
There are two methods in Objective C which are used to load and initialize a class.
+load and +initialize
1. In swift you can use "public override class func initialize()" to put your initialization code, please note that it will be called lazily.
Support for overriding load was removed in Swift 1.2
Here is what docs say about initialize method
"The runtime sends initialize to each class in a program just before the class, or any class that inherits from it, is sent its first message from within the program. The runtime sends the initialize message to classes in a thread-safe manner. Superclasses receive this message before their subclasses."
I'm playing with the swift language and i have a question on get/set properties. I think that it makes no sense to let the inner variable be public when the value is managed by a computed property. So I think that making this private to the class is a good practise. As I'm still learning maybe some of you could give me other ideas to leave it public.
class aGetSetClass{
private var uppercaseString : String
var upperString : String {
get {
return uppercaseString
}
set (value) {
self.uppercaseString = value.uppercaseString
}
}
init(){
uppercaseString = "initialized".uppercaseString
}
}
var instance3 = aGetSetClass()
println(instance3.upperString) // INITIALIZED
instance3.upperString = "new"
// println(instance3.uppercaseString) // private no access
println(instance3.upperString) // NEW
instance3.upperString = "new123new"
println(instance3.upperString) // NEW123NEW
The only way I could think of public access is either to make it as private set and then use a public set function instead:
public private(set) uppercaseString: String
public func setUpperString(string: String) {
uppercaseString = string.uppercaseString
}
Or make it public and use a didSet which sets itself under a certain condition (very inefficient for long strings):
public uppercaseString: String {
didSet {
if uppercaseString != uppercaseString.uppercaseString {
uppercaseString = uppercaseString.uppercaseString
}
}
}
These implementations use direct public access but your version is in my perspective the better / "swifter" way.
In this post there's a very interesting way of updating UI threads using a static extension method.
public static void InvokeIfRequired(this Control c, Action<Control> action)
{
if(c.InvokeRequired)
{
c.Invoke(() => action(c));
}
else
{
action(c);
}
}
What I want to do, is to make a generic version, so I'm not constrained by a control. This would allow me to do the following for example (because I'm no longer constrained to just being a Control)
this.progressBar1.InvokeIfRequired(pb => pb.Value = e.Progress);
I've tried the following:
public static void InvokeIfRequired<T>(this T c, Action<T> action) where T : Control
{
if (c.InvokeRequired)
{
c.Invoke(() => action(c));
}
else
{
action(c);
}
}
But I get the following error that I'm not sure how to fix. Anyone any suggestions?
Error 5 Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type
replace :
c.Invoke(() => action(c));
with :
c.Invoke(action, c);
This is a well known error with lambdas and anonymous methods:
Convert this delegate to an anonymous method or lambda
Your code just needs a cast to compile:
public static void InvokeIfRequired<T>(this T c, Action<T> action) where T : Control
{
if (c.InvokeRequired)
{
c.Invoke((Action<T>)((control) => action(control)));
}
else
{
action(c);
}
}
Try this slight varient:
public static void InvokeIfRequired<T>(this T c, Action<T> action) where T : Control
{
if (c.InvokeRequired)
{
c.Invoke((Action<T>)(() => action(c)));
}
else
{
action(c);
}
}
You need to cast it as a Delegate type. Kinda stupid I know. I can't really give you a good reason why a lambda expression isn't implicitly assignable as a delegate.