Problem with access to property

Hello,

I have an beginner problem.

I have an object like this:

object.atLeastToUse.limit.min
object.atLeastToUse.value
object.atLeastToUse.limit.max

Now I want, that the access to object.atLeastToUse.value is public get and set,
also get and set form limit.min" and limit.maxmust be able fromobjectlikeself.atLeastToUse.limit.minandself.atLeastToUse.limit.max```.

But the access form object.atLeastToUse.limit.min and object.atLeastToUse.limit.max must be get only.

Hello and welcome to the Swift Forums!

Your question was a bit difficult to parse, but I think I know what you mean now.

You have something like this:

struct SpecialThing {
    struct Requirements {
        struct Limit {
            var min: Int
            var max: Int
        }
        var value: Int
        var limit: Limit
    }
    var atLeastToUse: Requirements
}

(Side note: you may want to consider using ClosedRange<Int> from the Standard Library instead of a custom Limit type.)

You want to make limit settable within SpecialThing but not outside.

I believe the only way to achieve this is by putting SpecialThing in a separate file and using fileprivate(set) var limit: Limit.

Just to add to what @tem already wrote: you can read more about access control in the official documentation at Swift 5.5 Access Control. The documentation has some good examples and you're looking for section "Getters and Setters" with the following example code:

    struct TrackedString {
    private(set) var numberOfEdits = 0
    var value: String = "" {
        didSet {
            numberOfEdits += 1
        }
    }
}

In that example, numberOfEdits can be read from the "outside", but it is only updated internally.

1 Like

Unfortunately, it's a bit more complicated.
I want to use it for a slider.
The slider has an absolute range from 0 to 50.
But the relative range has to be limited.
For example, I can select a maximum of 50 students, but if I have already selected 20 girls on the first slider, I can only select a maximum of 30 girls on the second.
But the whole thing should also work without a GUI.
I have ...

homework.projects.participant.girls.limit.max --> set only from participant, get public
homework.projects.participant.girls.value --> set and get public
homework.projects.participant.girls.limit.max --> set only from participant, get public

Okay, but how does that change the problem? Change the property names and the solution is still the same, in my opinion. Can you be more specific about why the solution doesn't work for you? Are you unable to put participant in a separate file?

struct Limit {

    private var minValue : UInt8
    
    var min : UInt8 {
        get {
            return self.minValue
        }
        set(_newValue) {
            if(_newValue <= self.maxValue) {
                self.minValue = _newValue
            } else {
                self.minValue = self.maxValue
                self.maxValue = _newValue
            }
        }
            
    }

    private var maxValue : UInt8
    
    var max : UInt8 {
        get {
            return self.maxValue
        }
        set(_newValue) {
            if(_newValue >= self.minValue) {
                self.maxValue = _newValue
            } else {
                self.maxValue = self.minValue
                self.minValue = _newValue
            }
        }
    }

    init(_min : UInt8, _max : UInt8) {
        self.minValue = Swift.min(_min, _max)
        self.maxValue = Swift.max(_min, _max)
    }

}
class LimitedUInt8 {

    static let min : UInt8 = 0
    static let max : UInt8 = 50

    private var limitValue : Limit = Limit(_min: LimitedUInt8.min, _max: LimitedUInt8.max)
    var limit : Limit {
        get {
            return self.limitValue
        }
        set(_newLimits) {
            let newMin : UInt8 = Swift.max(Swift.min(_newLimits.min, _newLimits.max), LimitedUInt8.min)
            let newMax : UInt8 = Swift.min(Swift.max(_newLimits.min, _newLimits.max), LimitedUInt8.max)
            self.limitValue = Limit(_min: newMin, _max: Swift.min(newMax, LimitedUInt8.max))
            if(self.value < newMin || self.value > newMax) {
                self.value = self.value
            }
        }
    }

    @Published var value : UInt8 = 0 {
        didSet {
            if(self.value < self.limitValue.min) {
                self.value = self.limitValue.min
            } else if (self.value > self.limitValue.max) {
                self.value = self.limitValue.max
            }
        }
    }

    init(_value : UInt8, _limit: Limit) {
        let newMin : UInt8 = Swift.max(Swift.min(_limit.min, _limit.max), LimitedUInt8.min)
        let newMax : UInt8 = Swift.min(Swift.max(_limit.min, _limit.max), LimitedUInt8.max)
        self.limitValue = Limit(_min: newMin, _max: Swift.min(newMax, LimitedUInt8.max))
        if(_value < newMin) {
            self.value = newMin
        } else if(self.value > newMax) {
            self.value = newMax
        } else {
            self.value = _value
        }
    }

    convenience init(_value : UInt8, _min: UInt8, _max: UInt8) {
        self.init(_value: _value, _limit: Limit(_min: _min, _max: _max))
    }

    convenience init(_value : UInt8) {
        self.init(_value: _value, _limit: Limit(_min: LimitedUInt8.min, _max: LimitedUInt8.max))
    }

}

And LimitedUInt8 is used in multiple classes.
The LimitedUInt8.limit.min and LimitedUInt8.limit.max must be only allowed to set in the class were it's a property, but not XYZ.LimitedUInt8.limit.min

I still don't see why you can't make LimitedUInt8.limit private(set) or fileprivate(set). LimitedUInt8 will be able to set it, but it will be read only for everyone else.

I need it so that the object XYZ in which I use LimitedUInt8 as a data type for a property can set the value. But if you access from outside, value has to be read and set, but limit only has to be read.
If I were to set the limit to private, the XYZ object would no longer be able to set it.
And fileprivate (set) doesn't work either because I need LimitedUInt8 in multiple classes. Or I don't understand fileprivate (set).

Okay, I believe that isn't possible. One way to work around it might be to have a public read-only limit property on XYZ and a private read-write _limit property, and keep them in sync. To simplify that, perhaps you could make LimitedUInt8 into a property wrapper, which could be directly accessed within XYZ via the synthesized private property _limit. However, using a property wrapper merely to implement access control seems questionable.

Terms of Service

Privacy Policy

Cookie Policy