Swift 2 version of returning optional variables? - swift

I'm trying to implement getters/setters for properties. In the computed property, I'm returning the _locationManager, but also initializing the first time only:
var _locationManager: CLLocationManager? { get set }
var locationManager: CLLocationManager {
if let manager = _locationManager {
return manager
}
_locationManager = CLLocationManager()
return _locationManager!
}
Is there a more Swift-like version of the above statement? For example, in C# I can do something like this:
var locationManager: CLLocationManager {
return _locationManager ?? (_locationManager = CLLocationManager())
}
This is saying return _locationManager, or initialize plus return it. Does Swift have some kind of shorthand or another way for this scenario?
Update:
Below is another version. I'm trying to stick with a computed property so it can be used in protocol extensions and/or able to wire up a delegate in the process etc:
var locationManager: CLLocationManager {
return _locationManager ?? {
self._locationManager = CLLocationManager()
return self._locationManager!
}()
}

you could use a lazy property for this:
lazy var locationManager: CLLocationManager = CLLocationManager()
a lazy property gets initialized only when it is first used.

If you're really desperate to, you can do something like you're asking, but it's not terribly pretty. However, in the example you quoted, you should use lazy instantiation as Palle answered.
class Test {
}
var _test: Test?
var test: Test {
get {
return _test ?? { _test = Test() ; return _test! }()
}
}
Declaring a closure like this gets you the 'cute' one line getter, but I would leave it as you've got it because it's clearer.

Related

optionals with get and set

Hello I been researching the proper way to implement this and I found multiple articles but not the best correct way to implement this. Lets say I have a variable test, which is an optional and I would like to add some getters and setters. The problem that I have is the variable will be nil when the view loads, but I keep getting an error right on the get function that says: EXEC_BAD_ACCESS. I know the reason why I am getting this but also the system will not allow me to just add a setter by itself, any ideas to work with this? Thank you for your help
code:
var test: String? {
get {
return self.test
}
set {
//some logic
test = logic response
}
}
override func viewdidload(){
super.viewdidload()
//some logic
test = newValue
}
Your code has many syntax errors :)
However you are not looking for a getter & setter, what you want is the willSet observer.
class Controller: UIViewController {
var test: String? {
willSet {
// custom logic
self.test = newValue
}
}
override func viewDidLoad() {
super.viewDidLoad()
test = "my value"
}
}

Cannot assign to property: 'xxxx' is a get-only property

I'm using a computed property to get the last book in my books array. However, it seems I can't use this property to directly set a book's position property, as my attempt below shows:
struct Book {
var position: CGPoint?
}
class ViewController: UIViewController {
var books = [Book]()
var currentBook: Book {
return books[books.count - 1]
}
func setup() {
// Compiler Error: Cannot assign to property: 'currentBook' is a get-only property
currentBook.position = CGPoint.zero
}
}
The following works but I'd like it to be more readable and a single line.
books[books.count - 1].position = CGPoint.zero
I could use a function to return the current book but using a property would be cleaner. Is there another way?
The error occurs because you did not tell the compiler what to do if the value of currentBook is mutated. The compiler assumes it is immutable.
Just add a setter so that the compiler knows what to do when you set the value:
var currentBook: Book {
get { return books[books.count - 1] }
set { books[books.count - 1] = newValue }
}
Or, consider using books.last!:
books.last!.position = CGPoint.zero

Weak keyword with computed properties

private weak var _delegate: SomeClassDelegate?
weak var delegate: SomeClassDelegate? {
get {
return _delegate
}
set {
_delegate = newValue
}
}
This is valid code. Is there is any sense in using weak keyword with computed delegate property? Logically no; how compiler will process through this code?
Is there is any sense in using weak keyword with computed delegate property?
Not only is it sensible to do so, but it’s important to do so. This computed property is your public interface to this private hidden property. If the computed property lacks the weak qualifier, callers will draw incorrect conclusions about the underlying semantics.
Consider:
class SomeClass {
private weak var _delegate: SomeClassDelegate?
var delegate: SomeClassDelegate? { // whoops; this should be `weak`
get { return _delegate }
set { _delegate = newValue }
}
}
And
class CustomDelegate: SomeClassDelegate { ... }
Then
let object = SomeClass()
object.delegate = CustomDelegate()
In the absence of the the weak qualifier on the computed property and without diving into the implementation details, the programmer might incorrectly conclude that the above is fine. But it’s not. Because the underlying _delegate is weak, this CustomDelegate() instance will be deallocated immediately, and the object will end up with no delegate object. And there’s no compiler warning about this behavior.
If, however, we fix SomeClass like so:
class SomeClass {
private weak var _delegate: SomeClassDelegate?
weak var delegate: SomeClassDelegate? { // great; matches underlying semantics
get { return _delegate }
set { _delegate = newValue }
}
}
Then the programmer will receive a very helpful warning:
let object = SomeClass()
object.delegate = CustomDelegate() // results in "Instance will be immediately deallocated because property 'delegate' is 'weak'"
They’ll then correctly deduce that they should keep their own strong reference to this CustomDelegate for the code to work properly.
So, bottom line, you don’t technically need the weak qualifier on the computed property that is backed by a private weak stored property, but it’s prudent to do so to avoid mysterious bugs and/or misunderstandings about the underlying semantics.
Computed properties aren't retain by ARC, so you don't need to mark it as weak.
Only one pros that I know about is to ensure that property could be nil in future. You cannot declare it as:
weak var youProperty: YourType {
get {
return _yourProperty
}
set {
_yourProperty = newValue
}
}

swift setter causing exc_bad_access

I have a simple class below
import Foundation
public class UsefulClass: NSObject{
var test:NSNumber{
get{return self.test}
set{
println(newValue)
self.test = newValue
}
}
override init() {
super.init()
self.test = 5;
}
}
and I'm initializing it here
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var testClass = UsefulClass()
}
}
But it results in xcode printing out 200 5s and then crashing due to EXC_BAD_ACCESS code = 2. Why does this happen?
#vadian has provided a solution in his answer, which should fix your problem. Let me just explain what's happening.
You have created a computed property, i.e. a property which is not backed by a variable, instead both the getter and the setter do some processing, usually on another stored property, in order to respectively return a value and set a new value.
This is your computed property:
var test: NSNumber {
get { return self.test }
set {
println(newValue)
self.test = newValue
}
}
Look at the getter implementation:
return self.test
What does it do? It reads the test property of the current instance, and returns it. Which is the test property? It's this one:
var test: NSNumber {
get { return self.test }
set {
println(newValue)
self.test = newValue
}
}
Yes, it's the same property. What your getter does is to recursively and indefinitely calling itself, until a crash happen at runtime.
The same rule applies to the setter:
self.test = newValue
it keeps invoking itself, until the app crashes.
Swift variables are synthesized properties by default.
In the most cases this is sufficient (it's recommended to prefer Swift types)
var test: Int
override init() {
super.init()
test = 5
}
If you need to do something after a variable is set, use
var test: Int {
didSet{
println("\(oldValue) - \(newValue)")
}
}
your code sets the variable permanently by calling the setter which calls the setter which …
It's an infinite loop; your setter is recursively calling itself.
var test: NSNumber {
set {
test = newValue
}
}
This compiles fine, and an Objective-C programmer might expect no loop due to instead setting a "backing ivar" such as _test rather than re-calling the setter method.
But property-backing instance variable _ivars do not exist in Swift for computed properties unless you create them yourself.

Set value of read-only stored property during initializing in Swift

I want to implement my custom MKAnnotation. I took a look at MKAnnotation protocol(MKAnnotation.h).
It's as follow:
//
// MKAnnotation.h
// MapKit
//
// Copyright (c) 2009-2014, Apple Inc. All rights reserved.
//
protocol MKAnnotation : NSObjectProtocol {
// Center latitude and longitude of the annotation view.
// The implementation of this property must be KVO compliant.
var coordinate: CLLocationCoordinate2D { get }
// Title and subtitle for use by selection UI.
#optional var title: String! { get }
#optional var subtitle: String! { get }
// Called as a result of dragging an annotation view.
#optional func setCoordinate(newCoordinate: CLLocationCoordinate2D)
}
Please note the coordinate property (which is a read-only stored property).
And here is how I've implemented this protocol:
class RWDefaultPin: NSObject, MKAnnotation {
var title:String = ""
var subtitle:String = ""
var groupTag:String = ""
var coordinate: CLLocationCoordinate2D { get {
return self.coordinate // this is obviously wrong because property's trying to return itself
} };
init(coordinate:CLLocationCoordinate2D) {
super.init()
self.coordinate = coordinate
}
}
But obviously compiler complaints on my init method where I'm trying to assign to my coordinate property Cannot assign to 'coordinate' in 'self' obviously because it's a read-only property.
Previously in Objective-C we could overcome this issue as properties were backed by ivars.
I wish there was access modifier in Swift so I could define a private property in my class and set its value on init, and returning its value on get action of coordinate, but there is no such thing!
I don't quiet know how to fix this issue in Swift, or maybe I need to make it wide open and change my coordinate to be readable/writable?
You should be able to just add a setter to it and store the information in an inner coordinate value. Since you have a getter it is still conforming to the protocol:
var innerCoordinate: CLLocationCoordinate2D
var coordinate: CLLocationCoordinate2D {
get {
return self.innerCoordinate
}
set {
self.innerCoordinate = newValue
}
};
init(coordinate:CLLocationCoordinate2D) {
super.init()
self.innerCoordinate = coordinate
}
This is actually how I implement readonly and private properties (with protocols and the factory pattern). I setup protocols with the public interface and classes with private variables and setters. It is actually super clean way to setup your code (and gets around the lack of protected/private properties in Swift).
Here is a abstracted example of what I am talking about (if you care):
// this is your MKAnnotation in this example
protocol SomeProtocol {
var getterProperty: String { get }
var setterProperty: String { set get }
func publicFunction(someStirng: String) -> ();
}
// setup a function that returns a class conforming to your needed protocol
func SomeClassMaker() -> SomeProtocol {
// your internal class that no one can access unless by calling the maker function
class SomeClassInternal: NSObject, SomeProtocol {
// private and no one can get to me!
var innerSetterProperty = "default setter";
var getterProperty = "default getter"
var setterProperty: String {
get {
return self.innerSetterProperty;
}
set {
"hit"
self.innerSetterProperty = newValue
}
}
func publicFunction(someString: String) -> () {
// anyone get me
self.getterProperty = someString;
}
func privateFunction() -> () {
// no one can get me except internal functions
}
}
return SomeClassInternal();
}
// create the class
var classInstance = SomeClassMaker();
// totally fine!
classInstance.setterProperty = "secret string"
// prints "secret string"
classInstance.setterProperty;
// error! no public setter for "getter"
classInstance.getterProperty = "another secret"
classInstance.publicFunction("try secret again")
// prints "try secret again"
let blahed = classInstance.getterProperty
// error!
classInstance.privateFunction()
Even though the property is { get } in the protocol, that is just establishing a minimum criteria. It's perfectly acceptable to define it as read-write:
class MyAnnotation:NSObject, MKAnnotation
{
var coordinate:CLLocationCoordinate2D
init(coordinate:CLLocationCoordinate2D) {
self.coordinate = coordinate
}
}
Or, if you really want to keep it as read-only, you can use let:
class MyAnnotation:NSObject, MKAnnotation
{
let coordinate:CLLocationCoordinate2D
init(coordinate:CLLocationCoordinate2D) {
self.coordinate = coordinate
}
}