Zax*_*nov 121 properties objective-c swift
我正在尝试使用新的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
Run Code Online (Sandbox Code Playgroud)
出于特定目的,我们不能直接触摸秒,分和小时,并且只允许使用方法逐秒递增.只有这种方法可以通过使用实例变量的技巧来更改值.
由于Swift中没有这样的东西,我试图找到一个等价物.如果我这样做:
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++
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这可行,但任何人都可以直接改变属性.
也许我已经在Objective-C中设计了一个糟糕的设计,这就是为什么潜在的新Swift等价物没有意义.如果没有,如果有人有答案,我将非常感激;)
也许Apple承诺的未来访问控制机制就是答案?
谢谢!
Eth*_*han 348
只需在属性声明前加上前缀private(set)
,如下所示:
public private(set) var hours: UInt = 0
public private(set) var minutes: UInt = 0
public private(set) var seconds: UInt = 0
Run Code Online (Sandbox Code Playgroud)
private
将其保存在源文件的本地,同时internal
将其保留在模块/项目的本地.
private(set)
创建一个read-only
属性,同时private
设置属性set
和get
私有属性.
eli*_*lon 20
做你想做的事有两种基本方法.第一种方法是拥有一个私有属性和一个返回该属性的公共计算属性:
public class Clock {
private var _hours = 0
public var hours: UInt {
return _hours
}
}
Run Code Online (Sandbox Code Playgroud)
但这可以用不同的,更短的方式实现,如"Swift编程语言"一书的"访问控制"一节所述:
public class Clock {
public private(set) var hours = 0
}
Run Code Online (Sandbox Code Playgroud)
作为旁注,您必须在声明公共类型时提供公共初始化程序.即使您为所有属性提供默认值,也init()
必须明确定义public:
public class Clock {
public private(set) var hours = 0
public init() {
hours = 0
}
// or simply `public init() {}`
}
Run Code Online (Sandbox Code Playgroud)
在讨论默认初始化程序时,本书的相同部分也对此进行了解释.
由于没有访问控制(意味着您无法根据呼叫者的身份制定不同的访问合同),以下是我现在要做的事情:
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() }
}
Run Code Online (Sandbox Code Playgroud)
这仅仅增加了直接访问计数器的间接级别; 另一个类可以制作一个Clock然后直接访问它的计数器.但是这个想法 - 即我们试图达成的合同 - 是另一个类应该只使用Clock的顶级属性和方法.我们不能强制执行该合同,但实际上在Objective-C中实施也几乎是不可能的.
实际上,访问控制(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++
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这与 Objective C 中的相同,只是实际存储的属性在公共接口中可见。
在 swift 中你还可以做一些更有趣的事情,你也可以在 Objective C 中做,但在 swift 中可能更漂亮(在浏览器中编辑,我没有测试它):
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++
}
}
Run Code Online (Sandbox Code Playgroud)