Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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?

like image 534
Amir Rezvani Avatar asked Jun 09 '14 23:06

Amir Rezvani


People also ask

How do I make a Swift property read-only?

In swift, we can create a read-only property by only defining a getter for a variable. Meaning no setter! Since the variable only has a getter, the compiler will throw an error when we try to assign a value to “sum”.

Which type of property is initialized when it is accessed first in Swift?

Classes, structures and enumerations once declared in Swift 4 are initialized for preparing instance of a class. Initial value is initialized for stored property and also for new instances too the values are initialized to proceed further.

Do you have to initialize variables in Swift?

Variables and constants do not require initialization when declared. However, the variable or constant requires type annotation so that when the compiler reads the code line-by-line, it can determine the data type at the time of the build. A Use of undeclared type error will be thrown otherwise.

What does init () do in Swift?

Swift init() Initialization is the process of preparing an instance of a class, structure, or enumeration for use. This process involves setting an initial value for each stored property on that instance and performing any other setup or initialization that is required before the new instance is ready for use.


1 Answers

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()
like image 172
Firo Avatar answered Sep 30 '22 13:09

Firo