Próbuję coś wymyślić w nowym języku Apple Swift. Powiedzmy, że robiłem coś podobnego do tego w Objective-C. mamreadonly
właściwości i nie można ich zmieniać indywidualnie. Jednak przy użyciu określonej metody właściwości są zmieniane w logiczny sposób.
Biorę następujący przykład, bardzo prosty zegar. Napisałbym to w 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
W określonym celu nie możemy bezpośrednio dotykać sekund, minut i godzin, a przy użyciu metody można tylko zwiększać sekundę po sekundzie. Tylko ta metoda może zmieniać wartości przy użyciu sztuczek zmiennych instancji.
Ponieważ w Swift nie ma takich rzeczy, próbuję znaleźć odpowiednik. Jeśli to zrobię:
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++
}
}
}
}
To by zadziałało, ale każdy mógłby bezpośrednio zmienić właściwości.
Może miałem już zły projekt w Objective-C i dlatego potencjalny nowy odpowiednik Swift nie ma sensu. Jeśli nie i jeśli ktoś ma odpowiedź, byłbym bardzo wdzięczny;)
Może obiecane przez Apple przyszłe mechanizmy kontroli dostępu są odpowiedzią?
Dzięki!
źródło
Odpowiedzi:
Po prostu poprzedź deklarację właściwości
private(set)
, na przykład:private
utrzymuje go lokalnie w pliku źródłowym, podczas gdyinternal
zachowuje go lokalnie dla modułu / projektu.private(set)
tworzyread-only
właściwość, jednocześnieprivate
ustawiając obieset
iget
jako prywatną.źródło
Istnieją dwa podstawowe sposoby robienia tego, co chcesz. Pierwszy sposób polega na posiadaniu własności prywatnej i publicznej obliczonej właściwości, która zwraca tę własność:
Ale można to osiągnąć w inny, krótszy sposób, jak podano w sekcji „Kontrola dostępu” książki „The Swift Programming Language” :
Na marginesie, podczas deklarowania typu publicznego MUSISZ podać publiczny inicjator. Nawet jeśli podasz wartości domyślne dla wszystkich właściwości,
init()
należy je zdefiniować jawnie publicznie:Jest to również wyjaśnione w tej samej sekcji książki, gdy mowa o domyślnych inicjatorach.
źródło
Ponieważ nie ma kontroli dostępu (co oznacza, że nie można zawrzeć umowy dostępu, która różni się w zależności od tego, kto dzwoni), oto co bym teraz zrobił:
To tylko dodaje pewien poziom pośredni, jakby bezpośredni, dostęp do licznika; inna klasa może utworzyć zegar, a następnie uzyskać bezpośredni dostęp do jego licznika. Ale pomysł - tj. Kontrakt, który próbujemy zawrzeć - jest taki, że inna klasa powinna używać tylko właściwości i metod najwyższego poziomu Zegara. Nie możemy wyegzekwować tego kontraktu, ale w rzeczywistości było to prawie niemożliwe do wyegzekwowania również w celu C.
źródło
W rzeczywistości kontrola dostępu (która nie istnieje jeszcze w Swift) nie jest tak egzekwowana, jak mogłoby się wydawać w celu C. Ludzie mogą modyfikować zmienne tylko do odczytu, jeśli naprawdę tego chcą. Po prostu nie robią tego z publicznym interfejsem klasy.
Możesz zrobić coś podobnego w Swift (wytnij i wklej swój kod plus kilka modyfikacji, nie testowałem tego):
co jest tym samym, co masz w Objective C, z wyjątkiem tego, że rzeczywiste przechowywane właściwości są widoczne w interfejsie publicznym.
W swifcie można też zrobić coś ciekawszego, co też da się zrobić w Objective C, ale chyba ładniej jest w swifcie (edytowane w przeglądarce, nie testowałem):
źródło