Swift의 읽기 전용 및 계산되지 않은 변수 속성


126

새로운 Apple Swift 언어로 무언가를 찾으려고합니다. Objective-C에서 다음과 같은 작업을 수행했다고 가정 해 봅시다. 내가 가진 readonly속성을, 그들은 개별적으로 변경할 수 없습니다. 그러나 특정 방법을 사용하면 속성이 논리적으로 변경됩니다.

다음 예제를 보자. 매우 간단한 시계. 나는 Objective-C로 이것을 쓸 것이다.

@interface Clock : NSObject

@property (readonly) NSUInteger hours;
@property (readonly) NSUInteger minutes;
@property (readonly) NSUInteger seconds;

- (void)incrementSeconds;

@end

@implementation Clock

- (void)incrementSeconds {
     _seconds++;

     if (_seconds == 60) {
        _seconds = 0;
        _minutes++;

         if (_minutes == 60) {
            _minutes = 0;
            _hours++;
        }
    }
}

@end

특정 목적을 위해 초, 분 및 시간을 직접 만질 수 없으며 방법을 사용하여 초 단위로만 증가시킬 수 있습니다. 이 방법 만 인스턴스 변수의 트릭을 사용하여 값을 변경할 수 있습니다.

스위프트에는 그러한 것이 없기 때문에 동등한 것을 찾으려고 노력하고 있습니다. 내가 이렇게하면 :

class Clock : NSObject {

    var hours:   UInt = 0
    var minutes: UInt = 0
    var seconds: UInt = 0

    func incrementSeconds() {

        self.seconds++

        if self.seconds == 60 {

            self.seconds = 0
            self.minutes++

            if self.minutes == 60 {

                self.minutes = 0
                self.hours++
            }
        }
    }
}

작동하지만 누구나 속성을 직접 변경할 수 있습니다.

어쩌면 이미 Objective-C에서 디자인이 잘못되어 새로운 Swift에 해당하는 것이 적합하지 않은 이유입니다. 그렇지 않은 경우 누군가 대답이 있으면 매우 감사합니다.)

아마도 애플이 약속 한 미래의 액세스 제어 메커니즘 이 답일까요?

감사!


2
액세스 제어가 답입니다. 실제 데이터에 개인 속성을 사용하는 동안 읽기 전용 계산 속성을 생성합니다.
레오 나탄

Apple이 버그가 얼마나 심각한 지 알려주기 위해 버그 보고서 (향상된 기능)를 열어야합니다.
레오 나탄

1
신규 사용자 : 하단으로 스크롤 ...
Gustaf Rosenblad

2
@Ethan의 답변을 올바른 것으로 표시하십시오.
phatmann

답변:


356

다음과 private(set)같이 속성 선언에 접두사를 붙이십시오 .

public private(set) var hours:   UInt = 0
public private(set) var minutes: UInt = 0
public private(set) var seconds: UInt = 0

private소스 파일에 internal로컬로 유지하고 모듈 / 프로젝트에 로컬로 유지합니다.

private(set)read-only속성을 작성하는 동안 및 비공개로 private설정합니다 .setget


28
소스 파일에 로컬로 유지하려면 "private", 모듈 / 프로젝트에 로컬로 유지하려면 "internal" private (set)은 세트를 개인용으로 만 만듭니다. Private은 set 및 get 함수를 모두 private으로 만듭니다.
user965972

3
이 답변에 첫 번째 주석이 추가되어 더 완벽 해집니다.
Rob Norback

현재 (Swift 3.0.1) 액세스 제어 레벨이 변경되었습니다. "fileprivate"선언은 선언과 동일한 소스 파일의 코드로만 액세스 할 수 있습니다. " "비공개"선언은 선언의 즉각적인 범위 내에서 코드를 통해서만 액세스 할 수 있습니다.
쥬라기

20

원하는 것을 수행하는 두 가지 기본 방법이 있습니다. 첫 번째 방법은 개인 속성과 해당 속성을 반환하는 공용 계산 속성을 갖는 것입니다.

public class Clock {

  private var _hours = 0

  public var hours: UInt {
    return _hours
  }

}

그러나 "Swift Programming Language" 서적 의 "액세스 제어" 섹션에 설명 된 것과 같이 다른 방법으로 더 짧은 방법으로 달성 할 수 있습니다 .

public class Clock {

    public private(set) var hours = 0

}

참고로, 공개 유형을 선언 할 때는 공개 이니셜 라이저를 제공해야합니다. 모든 속성에 기본값을 제공하더라도 init()명시 적으로 public으로 정의해야합니다.

public class Clock {

    public private(set) var hours = 0

    public init() {
      hours = 0
    }
    // or simply `public init() {}`

}

이것은 기본 이니셜 라이저에 대해 이야기 할 때 책의 같은 섹션에서 설명됩니다.


5

액세스 제어가 없기 때문에 (발신자에 따라 다른 액세스 계약을 체결 할 수 없음을 의미) 다음은 현재 내가 수행 할 작업입니다.

class Clock {
    struct Counter {
        var hours = 0;
        var minutes = 0;
        var seconds = 0;
        mutating func inc () {
            if ++seconds >= 60 {
                seconds = 0
                if ++minutes >= 60 {
                    minutes = 0
                    ++hours
                }
            }
        }
    }
    var counter = Counter()
    var hours : Int { return counter.hours }
    var minutes : Int { return counter.minutes }
    var seconds : Int { return counter.seconds }
    func incrementTime () { self.counter.inc() }
}

이것은 단순히 카운터에 직접 액세스하기위한 수준의 간접적 인 추가를 추가합니다. 다른 클래스 Clock을 만든 다음 카운터에 직접 액세스 할 수 있습니다. 그러나 아이디어 , 즉 우리가 만들고자하는 계약은 다른 클래스가 Clock의 최상위 속성과 메서드 만 사용해야한다는 것입니다. 우리는 할 수 없습니다 그 계약을 집행 없지만 실제로 Objective-C에서도 시행하는 것은 거의 불가능했습니다.


그때 이후로 변경된 것 같습니다. 맞습니까? developer.apple.com/swift/blog/?id=5
Dan Rosenstark

1
@Yar,이 모든 질문 / 답변은 Swift에 액세스 제어가 추가되기 오래 전에 작성 되었습니다. Swift는 여전히 발전하고 있으므로 답변은 계속 구식입니다.
matt

2

실제로 Swift에는 존재하지 않는 액세스 제어는 Objective C에서 생각하는 것처럼 시행되지 않습니다. 사람들 원하는 경우 읽기 전용 변수를 직접 수정할 수 있습니다 . 그들은 단지 클래스의 공개 인터페이스로는하지 않습니다.

Swift에서 비슷한 작업을 수행 할 수 있습니다 (코드 잘라 내기 및 붙여 넣기 및 일부 수정, 테스트하지 않았습니다).

class Clock : NSObject {

    var _hours:   UInt = 0
    var _minutes: UInt = 0
    var _seconds: UInt = 0

    var hours: UInt {
    get {
      return _hours
    }
    }

    var minutes: UInt {
    get {
      return _minutes
    }
    }

    var seconds: UInt  {
    get {
      return _seconds
    }
    }

    func incrementSeconds() {

        self._seconds++

        if self._seconds == 60 {

            self._seconds = 0
            self._minutes++

            if self._minutes == 60 {

                self._minutes = 0
                self._hours++
            }
        }
    }
}

실제 저장된 속성이 공용 인터페이스에 표시된다는 점을 제외하고는 Objective C에있는 것과 동일합니다.

신속하게 목표 C에서도 할 수있는 더 흥미로운 것을 할 수는 있지만 신속하게 더 예쁘다 (브라우저에서 편집 했으므로 테스트하지 않았습니다).

class Clock : NSObject {

    var hours: UInt = 0

    var minutes: UInt {
    didSet {
      hours += minutes / 60
      minutes %= 60
    }
    }

    var seconds: UInt  {
    didSet {
      minutes += seconds / 60
      seconds %= 60
    }
    }

    // you do not really need this any more
    func incrementSeconds() {
        seconds++
    }
}

"사람은 읽기 전용 변수를 직접 수정할 수 있습니다"-정확히 무엇을 의미합니까? 어떻게?
user1244109

Objective C를 언급하고있었습니다. Objective C에서는 Objective C Runtime API를 통해 클래스에 대한 모든 것에 동적으로 액세스 할 수 있습니다.
Analog File

나는 당신이 신속하게 그것을 암시한다는 것을 어떻게 든 이해했습니다. 궁금해 감사합니다
user1244109
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.