Reputation: 13551
When I create a setter such as:
var masterFrame: CGRect {
set {
_imageView.frame = newValue
_scrollView.frame = newValue
}
}
It's forcing me to make a getter, which I don't want to do.
Is there any way to create a setter in Swift without a getter?
Upvotes: 40
Views: 26304
Reputation: 907
You can give access modifier to set
for property and on didSet
you can assign it to _imageView.frame
& _scrollView.frame
private(set) var masterFrame: CGRect {
didSet {
_imageView.frame = masterFrame
_scrollView.frame = masterFrame
}
}
Upvotes: 1
Reputation: 3607
Use didSet
instead:
var masterFrame:CGRect {
didSet {
_imageView.frame = masterFrame
_scrollView.frame = masterFrame
}
}
Upvotes: 12
Reputation: 86165
Well if I really have to, I would use this.
Swift compiler supports some attributes on getters, so you can use @available(*, unavailable)
:
public subscript(index: Int) -> T {
@available(*, unavailable)
get {
fatalError("You cannot read from this object.")
}
set(v) {
}
}
This will clearly deliver your intention to the code users.
Upvotes: 28
Reputation: 128
I have found one exception where I really like a setter only variable which is when I am passing a closure as the only parameter in a method for the sole purpose of saving it of for later execution.
I implement it as a method as follows:
typealias ThemeSetter = () -> ()
class Theme {
fileprivate var themeSetters:[ThemeSetter] = []
class var shared: Theme {
struct Singleton {
static let instance = Theme()
}
return Singleton.instance
}
...
func setColor(_ entry:@escaping ThemeSetter) {
entry()
themeSetters.append(entry)
}
}
I can then call the method as follows:
Theme.shared.setColor({
self.navigationBar.barTintColor = Theme.shared.gameBarTint
})
But I don't like close paretheses after the close bracket, since I may have many lines in the closure.
So, knowing about Trailing Closures I can just change the code to look like this:
Theme.shared.setColor() {
self.navigationBar.barTintColor = Theme.shared.gameBarTint
}
This is perfectly okay and is the syntax that Apple shows for Trailing Closures. Since there is only the one parameter and being the minimalist that I am I am tempted to make the code even leaner and reduce it to this:
Theme.shared.setColor {
self.navigationBar.barTintColor = Theme.shared.gameBarTint
}
Which is again how Apple shows to do Trailing Closures; Except, this way is usually used for some sort of Predicate where the closure is used to tell the method how to do a sort or when the closure is used at the end of an asynchronous function call as a completion closure. What I want is to assign the closure to ... Something.
If I replace the method for setColor with a variable it looks like this:
var setColor:ThemeSetter? {
didSet {
if setColor != nil {
setColor?()
themeSetters.append(setColor!)
setColor = nil
}
}
}
Now the call looks like this:
Theme.shared.setColor = {
self.navigationBar.barTintColor = Theme.shared.gameBarTint
}
That equals sign means all the difference to be. It shows that I am assigning a closure and not running some function that uses the closure, even though it does. :') <- need emoticon here.
Final notes: This really has nothing to do with closures, it just shows how you can make a setter only variable, except that it still it returns a nil. It is not meant to protect the class from having the user accessing the variable for read like a true setter only would. Also, forgive the tutorial on Trailing Closures and Singletons.
I may not get enough Up Votes to be the correct answer but why is the correct answer, "No you can't! You must use a method call!". I say, "Ni" to that, who needs all that syntax. Just use a variable and don't read it back or if you do, don't have it return anything. kind of like Rudolf Adamkovic answer, which got 0 Up Votes.
Upvotes: 0
Reputation: 1967
Sure. You can just return a nil and make the type optional:
var color: MyColorEnum? {
get { return nil }
set {
switch newValue! {
case .Blue:
view.backgroundColor = UIColor.blueColor()
case .Red:
view.backgroundColor = UIColor.redColor()
}
}
}
Alternatively, you may use didSet
to avoid the issue all together:
var color: MyColorEnum! {
didSet {
switch color {
case .Blue:
view.backgroundColor = UIColor.blueColor()
case .Red:
view.backgroundColor = UIColor.redColor()
}
}
}
Upvotes: 6
Reputation: 24962
To have a "setter-only property", you can just have a simple function that sets the value; for example, if we have a private property called value
, we can have a setter method called, configureWithValue(value:String)
that updates the property but doesn't allow outside access to the property:
private var value:String
func configureWithValue(value:String) {
self.value = value
}
Upvotes: 10
Reputation: 13353
A set only property doesn't sound like it makes a lot of sense. You should probably use a method for that instead.
Or, just make the compiler happy and add a getter that you never call:
get {
return _imageView.frame
}
Upvotes: 11
Reputation: 3418
From the docs:
The getter is used to read the value, and the setter is used to write the value. The setter clause is optional, and when only a getter is needed, you can omit both clauses and simply return the requested value directly, as described in Read-Only Computed Properties. But if you provide a setter clause, you must also provide a getter clause.
Upvotes: 15