Swift中的只读和非计算variables属性

我试图找出新的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 

为了一个特定的目的,我们不能直接触摸秒,分和小时,只允许使用方法每秒增加一秒。 只有这种方法可以通过使用实例variables的技巧来改变值。

既然在Swift中没有这样的事情,我正试图find一个等价的东西。 如果我这样做:

 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中已经有了一个糟糕的devise,这就是为什么潜在的新的Swift等价物没有意义。 如果不是,如果有人有答案,我将非常感激;)

也许苹果公司承诺的未来访问控制机制是答案?

谢谢!

只需将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)创build一个read-only属性, private设置privateset

有两种基本的方式来做你想做的事情。 第一种方式是拥有一个私人财产和一个公共计算财产返回该财产:

 public class Clock { private var _hours = 0 public var hours: UInt { return _hours } } 

但是,这可以用另一种更短的方式来实现,如“Swift编程语言”一书的“访问控制”部分所述:

 public class Clock { public private(set) var hours = 0 } 

作为一个方面说明,你必须提供一个公共的初始化者时声明一个公共types。 即使你为所有属性提供默认值, init()必须显式定义public:

 public class Clock { public private(set) var hours = 0 public init() { hours = 0 } // or simply `public init() {}` } 

在这本书的同一部分,当谈到默认的初始化程序时也解释了这一点。

由于没有访问控制(这意味着你不能根据调用者的不同来访问合同),下面是我现在要做的:

 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() } } 

这只是增加了一个间接的层面,直接进入柜台; 另一个class可以做一个时钟,然后直接访问它的计数器。 但是这个想法 – 也就是我们想要做的合同 – 是另一个类只能使用Clock的顶层属性和方法。 我们不能执行这个合同,但实际上在Objective-C中执行也是不可能的。

实际上,访问控制(在Swift中还不存在)不像您在Objective C中那样执行。人们可以直接修改只读variables,如果他们真的想要的话。 他们只是不用这个类的公共接口来做。

你可以在Swift中做类似的事情(剪切和粘贴你的代码,加上一些修改,我没有testing它):

 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中的一样,除了实际存储的属性在公共接口中可见之外。

在swift中,你也可以做一些更有趣的事情,你也可以在Objective C中做,但是在swift中可能更漂亮(在浏览器中编辑,我没有testing它):

 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++ } }