Java ile gelen Swift ile oynamak, neden bir Sınıf yerine bir Yapı seçmek istersiniz? Daha az işlevsellik sunan bir Struct ile aynı şey gibi görünüyorlar. Neden seçmelisin?
Java ile gelen Swift ile oynamak, neden bir Sınıf yerine bir Yapı seçmek istersiniz? Daha az işlevsellik sunan bir Struct ile aynı şey gibi görünüyorlar. Neden seçmelisin?
Yanıtlar:
Swift'teki çok popüler WWDC 2015 talk Protokol Odaklı Programlamaya ( video , konuşma metni ) göre Swift, birçok durumda yapıları sınıflardan daha iyi yapan bir dizi özellik sunar.
Yapılar, nispeten küçük ve kopyalanabilir olmaları durumunda tercih edilir, çünkü kopyalama, sınıflarda olduğu gibi aynı örneğe birden çok referansa sahip olmaktan çok daha güvenlidir. Bu, bir değişkenin birçok sınıfa ve / veya çok iş parçacıklı bir ortamda aktarılması sırasında özellikle önemlidir. Değişkeninizin bir kopyasını her zaman başka yerlere gönderebiliyorsanız, değişkeninizin değerini altınızdaki değeri değiştirerek asla başka bir yer hakkında endişelenmenize gerek yoktur.
Structs ile, bir değişkenin tek bir örneğine erişmek / değiştirmek için bellek sızıntıları veya yarışan birden çok iş parçacığı hakkında endişelenmenize gerek yoktur. (Teknik açıdan daha fikirli olmak için, istisna, bir yapının bir kapatma içinde yakalanmasıdır, çünkü daha sonra kopyalanacak şekilde açıkça işaretlenmedikçe, örneğe bir referans yakalar).
Sınıflar da şişirilebilir çünkü sınıf yalnızca tek bir üst sınıftan miras alabilir. Bu bizi, sadece gevşek bir şekilde ilişkili olan birçok farklı yeteneği kapsayan büyük üst sınıflar yaratmaya teşvik ediyor. Protokolleri, özellikle protokollere uygulamalar sağlayabileceğiniz protokol uzantılarıyla kullanmak, bu tür davranışları elde etmek için sınıflara olan ihtiyacı ortadan kaldırmanıza olanak tanır.
Konuşma, sınıfların tercih edildiği şu senaryoları ortaya koyar:
- Örnekleri kopyalamak veya karşılaştırmak anlamlı değildir (örn. Pencere)
- Eşgörünüm ömrü dış etkilere bağlıdır (örn. TemporaryFile)
- Örnekler yalnızca "lavabolar" dır - harici duruma yalnızca yazma kanalları (egCGContext)
Yapıların varsayılan olması ve sınıfların yedek olması gerektiği anlamına gelir.
Öte yandan, Swift Programlama Dili belgeleri biraz çelişkilidir:
Yapı örnekleri her zaman değere, sınıf örnekleri de her zaman başvuruya göre geçirilir. Bu, farklı görevlere uygun oldukları anlamına gelir. Bir proje için gereken veri yapılarını ve işlevselliğini göz önünde bulundururken, her veri yapısının bir sınıf mı yoksa bir yapı olarak mı tanımlanacağına karar verin.
Genel bir kılavuz olarak, bu koşullardan biri veya daha fazlası geçerli olduğunda bir yapı oluşturmayı düşünün:
- Yapının birincil amacı, nispeten basit birkaç veri değerini kapsamaktır.
- Bu yapının bir örneğini atadığınızda veya aktardığınızda, kapsüllenmiş değerlerin başvurulmak yerine kopyalanmasını beklemek mantıklıdır.
- Yapı tarafından saklanan herhangi bir özellik, kendileri referanslı olmak yerine kopyalanması beklenen değer türleridir.
- Yapının özellikleri veya davranışı var olan başka bir türden devralması gerekmez.
Yapılar için iyi adaylara örnekler:
- Her ikisi de Double tipinde bir width özelliği ve height özelliği içeren geometrik bir şeklin boyutu.
- Bir seri içindeki aralıklara atıfta bulunmanın bir yolu, belki de her ikisi de Int türünde bir başlangıç özelliği ve bir uzunluk özelliği kapsülleme.
- 3D koordinat sistemindeki bir nokta, belki de her biri Double tipinde olan x, y ve z özelliklerini kapsayan.
Diğer tüm durumlarda, bir sınıf tanımlayın ve referans ile yönetilecek ve iletilecek o sınıfın örneklerini oluşturun. Uygulamada bu, çoğu özel veri yapısının yapı değil sınıf olması gerektiği anlamına gelir.
Burada varsayılan olarak sınıfları kullanmamız ve yapıları yalnızca belirli durumlarda kullanmamız gerektiği iddia edilmektedir. Sonuçta, değer türlerinin referans türlere karşı gerçek dünyadaki anlamını anlamanız gerekir ve daha sonra yapıların veya sınıfların ne zaman kullanılacağı hakkında bilinçli bir karar verebilirsiniz. Ayrıca, bu kavramların her zaman gelişmekte olduğunu ve Protokol Odaklı Programlama konuşması yapılmadan önce Swift Programlama Dili belgelerinin yazıldığını unutmayın.
In practice, this means that most custom data constructs should be classes, not structures.
okuduktan sonra, çoğu veri kümesinin sınıflar değil, yapılar olması gerektiğini nasıl anlarsınız? Bir şeyin bir yapı olması gerektiğinde ve "sınıfın daha iyi olduğu diğer tüm senaryolar" derken belirli bir kural seti verdiler.
Yapı örnekleri yığın üzerinde ve sınıf örnekleri yığın üzerinde tahsis edildiğinden, yapılar bazen çok daha hızlı olabilir.
Ancak, her zaman kendiniz ölçmeli ve benzersiz kullanım durumunuza göre karar vermelisiniz.
Ve Int
kullanarak veri türünü kaydırmanın 2 stratejisini gösteren aşağıdaki örneği ele alalım . Birden fazla alanın olduğu gerçek dünyayı daha iyi yansıtmak için 10 tekrarlanan değer kullanıyorum.struct
class
class Int10Class {
let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int
init(_ val: Int) {
self.value1 = val
self.value2 = val
self.value3 = val
self.value4 = val
self.value5 = val
self.value6 = val
self.value7 = val
self.value8 = val
self.value9 = val
self.value10 = val
}
}
struct Int10Struct {
let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int
init(_ val: Int) {
self.value1 = val
self.value2 = val
self.value3 = val
self.value4 = val
self.value5 = val
self.value6 = val
self.value7 = val
self.value8 = val
self.value9 = val
self.value10 = val
}
}
func + (x: Int10Class, y: Int10Class) -> Int10Class {
return IntClass(x.value + y.value)
}
func + (x: Int10Struct, y: Int10Struct) -> Int10Struct {
return IntStruct(x.value + y.value)
}
Performans,
// Measure Int10Class
measure("class (10 fields)") {
var x = Int10Class(0)
for _ in 1...10000000 {
x = x + Int10Class(1)
}
}
// Measure Int10Struct
measure("struct (10 fields)") {
var y = Int10Struct(0)
for _ in 1...10000000 {
y = y + Int10Struct(1)
}
}
func measure(name: String, @noescape block: () -> ()) {
let t0 = CACurrentMediaTime()
block()
let dt = CACurrentMediaTime() - t0
print("\(name) -> \(dt)")
}
Kod https://github.com/knguyen2708/StructVsClassPerformance adresinde bulunabilir.
GÜNCELLEME (27 Mar 2018) :
Swift 4.0, Xcode 9.2'den itibaren, iPhone 6S, iOS 11.2.6'da Sürüm derlemesini çalıştıran Swift Derleyici ayarı -O -whole-module-optimization
:
class
sürüm 2.06 saniye sürdüstruct
sürüm 4.17e-08 saniye sürdü (50.000.000 kat daha hızlı)(Varyanslar% 5'in altında çok küçük olduğu için artık birden fazla çalışmayı ortalama yapmıyorum)
Not : bütün modül optimizasyonu olmadan fark çok daha az dramatiktir. Birisi bayrağın gerçekte ne yaptığını gösterebilirse sevinirim.
GÜNCELLEME (7 Mayıs 2016) :
Swift 2.2.1, Xcode 7.3, iPhone 6S, iOS 9.3.1'de Sürüm derlemesini çalıştıran ve ortalama 5 çalışmanın ortalaması olan Swift Compiler ayarı -O -whole-module-optimization
:
class
sürüm 2.159942142s aldıstruct
sürüm 5.83E-08 aldı (37.000.000 kat daha hızlı)Not : Birisinin gerçek dünya senaryolarında, bir yapıda muhtemelen 1'den fazla alan olacağından bahsettiği gibi, 1 yerine 10 alanlı yapılar / sınıflar için testler ekledim. Şaşırtıcı bir şekilde, sonuçlar çok fazla değişmiyor.
ORİJİNAL SONUÇLAR (1 Haziran 2014):
(10 değil, 1 alanlı yapı / sınıfta koş)
Swift 1.2, Xcode 6.3.2'den itibaren, iPhone 5S, iOS 8.3'te Release derlemesini çalıştırıyor, ortalama 5'ten fazla çalışıyor
class
sürüm 9.788332333s aldıstruct
sürüm 0.010532942s aldı (900 kat daha hızlı)ESKİ SONUÇLAR (bilinmeyen zamandan)
(10 değil, 1 alanlı yapı / sınıfta koş)
MacBook Pro'mda sürüm oluşturma ile:
class
Sürüm 1,10082 saniye sürdüstruct
Versiyon (50 kat daha hızlı) 0,02324 saniye sürdüBunun için basit örneklerle özgeçmiş oluşturdum. https://github.com/objc-swift/swift-classes-vs-structures
yapılar hızla miras alamaz. Eğer istersen
class Vehicle{
}
class Car : Vehicle{
}
Derse git.
Hızlı yapılar değere göre geçer ve sınıf örnekleri referans ile geçer.
Yapı sabiti ve değişkenler
Örnek (WWDC 2014'te kullanılmıştır)
struct Point{
var x = 0.0;
var y = 0.0;
}
Nokta adlı bir yapı tanımlar.
var point = Point(x:0.0,y:2.0)
Şimdi x'i değiştirmeye çalışırsam. Geçerli bir ifade.
point.x = 5
Ama bir noktayı sabit olarak tanımlasam.
let point = Point(x:0.0,y:2.0)
point.x = 5 //This will give compile time error.
Bu durumda tüm nokta değişmez sabittir.
Bunun yerine bir sınıf Point kullandıysam bu geçerli bir ifadedir. Çünkü bir sınıfta değişmez sabit, sınıf değişkenine referans olarak sınıfın kendisine referans değildir (Sabitler olarak tanımlanan değişkenler olmadığı sürece)
Dikkate almanız gereken başka nedenler:
yapılar, kodda hiç bakım yapmanız gerekmeyen otomatik bir başlatıcı alır.
struct MorphProperty {
var type : MorphPropertyValueType
var key : String
var value : AnyObject
enum MorphPropertyValueType {
case String, Int, Double
}
}
var m = MorphProperty(type: .Int, key: "what", value: "blah")
Bunu bir sınıfta almak için başlatıcıyı eklemeniz ve başlatıcıyı korumanız gerekir ...
Gibi temel koleksiyon türleri Array
yapılardır. Bunları kendi kodunuzda ne kadar çok kullanırsanız, referansın aksine değere göre o kadar çok alışacaksınız. Örneğin:
func removeLast(var array:[String]) {
array.removeLast()
println(array) // [one, two]
}
var someArray = ["one", "two", "three"]
removeLast(someArray)
println(someArray) // [one, two, three]
Görünüşe göre değişmezlik ve değişebilirlik muazzam bir konudur, ancak birçok akıllı insan değişmezliğin - bu durumda yapılar - tercih edilir olduğunu düşünmektedir. Değişken ve değişmeyen nesneler
internal
kapsam dışında kullanılabilir olmasını istiyorsanız, başlatıcıyı kendiniz yazmanız gerekir .
mutating
hangi işlevlerin durumlarını değiştirdiği konusunda açık olmanız için işaretlemelisiniz . Ancak değer türleri olarak doğaları önemlidir. Birlikte bir yapı let
bildirirseniz, üzerinde herhangi bir mutasyon işlevini çağıramazsınız. WWDC 15 değer türleri ile daha iyi programlama videosu bu konuda mükemmel bir kaynaktır.
Struct'ın bir değer türü ve Class'ın bir referans türü olduğunu bildiğimizi varsayarsak .
Bir değer türünün ve bir referans türünün ne olduğunu bilmiyorsanız, bkz . Referanstan geçerken değere göre geçiş arasındaki fark nedir?
Dayanarak mikeash gönderide :
... Önce bazı aşırı, açık örneklere bakalım. Tamsayılar açık bir şekilde kopyalanabilir. Değer türleri olmalıdır. Ağ soketleri hassas bir şekilde kopyalanamaz. Referans türleri olmalıdır. X, y çiftleri gibi noktalar kopyalanabilir. Değer türleri olmalıdır. Diski temsil eden bir denetleyici makul bir şekilde kopyalanamaz. Bu bir referans türü olmalıdır.
Bazı türler kopyalanabilir, ancak her zaman olmasını istediğiniz bir şey olmayabilir. Bu onların referans türleri olması gerektiğini gösterir. Örneğin, ekrandaki bir düğme kavramsal olarak kopyalanabilir. Kopya orijinal ile tamamen aynı olmayacaktır. Kopyanın üzerine tıklanması orijinali etkinleştirmez. Kopya ekranda aynı yeri işgal etmez. Düğmeyi geçerseniz veya yeni bir değişkene koyarsanız, muhtemelen orijinal düğmeye başvurmak istersiniz ve yalnızca açıkça istendiğinde bir kopya oluşturmak istersiniz. Bu, düğme türünüzün bir referans türü olması gerektiği anlamına gelir.
Görünüm ve pencere denetleyicileri de buna benzer bir örnektir. Muhtemelen kopyalanabilir olabilirler, ama neredeyse hiçbir zaman yapmak istediğiniz şey bu değildi. Referans türleri olmalıdır.
Model türleri ne olacak? Sisteminizde bir kullanıcıyı temsil eden bir Kullanıcı türünüz veya bir Kullanıcı tarafından gerçekleştirilen bir eylemi temsil eden bir Suç türünüz olabilir. Bunlar oldukça uyumludur, bu yüzden muhtemelen değer türleri olmalıdır. Ancak, muhtemelen programınızın tek bir yerinde yapılan Kullanıcı Suçuna yönelik güncellemelerin programın diğer bölümleri tarafından görülmesini istersiniz. Bu, Kullanıcılarınızın bir referans türü olabilecek bir tür kullanıcı denetleyicisi tarafından yönetilmesi gerektiğini gösterir . Örneğin
struct User {} class UserController { var users: [User] func add(user: User) { ... } func remove(userNamed: String) { ... } func ... }
Koleksiyonlar ilginç bir durum. Bunlar diziler ve diziler gibi şeyleri içerir. Kopyalanabilir mi? Açıkçası. Kopyalamak kolay ve sık sık olmasını istediğiniz bir şey mi? Bu daha az açık.
Çoğu dil buna "hayır" der ve koleksiyonlarını referans türlerine dönüştürür. Bu Objective-C ve Java ve Python ve JavaScript ve aklıma gelen hemen hemen her dilde doğrudur. (Büyük bir istisna, STL toplama türlerine sahip C ++, ancak C ++ her şeyi garip bir şekilde yapan dil dünyasının çılgın delisidir.)
Swift, "evet" dedi, yani Dizi ve Sözlük ve Dize gibi türler sınıflardan ziyade yapılardır. Ödev üzerine kopyalanır ve parametre olarak iletilirler. Bu, kopya ucuz olduğu sürece tamamen mantıklı bir seçimdir ve Swift'in başarması çok zordur. ...
Ben şahsen derslerimi böyle adlandırmam. Ben genellikle UserController yerine benim UserManager adını ama fikir aynı
Ayrıca, bir işlevin her bir örneğini, yani paylaşılan bir işlevselliğe sahip olmadıklarını geçersiz kılmak zorunda kaldığınızda sınıfı kullanmayın .
Yani bir sınıfın birkaç alt sınıfına sahip olmak yerine. Bir protokole uygun çeşitli yapılar kullanın.
Yapılar için bir başka makul durum, eski ve yeni modelinizin bir delta / farkını yapmak istediğinizde. Referans türleri ile bunu kutudan çıkartamazsınız. Değer türleri ile mutasyonlar paylaşılmaz.
Bazı avantajlar:
Yapı Sınıftan çok daha hızlıdır. Ayrıca, mirasa ihtiyacınız varsa Class'ı kullanmalısınız. En önemli nokta Sınıf'ın referans tipi, Yapı ise değer tipidir. Örneğin,
class Flight {
var id:Int?
var description:String?
var destination:String?
var airlines:String?
init(){
id = 100
description = "first ever flight of Virgin Airlines"
destination = "london"
airlines = "Virgin Airlines"
}
}
struct Flight2 {
var id:Int
var description:String
var destination:String
var airlines:String
}
Şimdi her ikisinin de örneğini oluşturalım.
var flightA = Flight()
var flightB = Flight2.init(id: 100, description:"first ever flight of Virgin Airlines", destination:"london" , airlines:"Virgin Airlines" )
Şimdi bu örneği id, açıklama, hedef vb. değiştiren iki fonksiyona geçirelim.
func modifyFlight(flight:Flight) -> Void {
flight.id = 200
flight.description = "second flight of Virgin Airlines"
flight.destination = "new york"
flight.airlines = "Virgin Airlines"
}
Ayrıca,
func modifyFlight2(flight2: Flight2) -> Void {
var passedFlight = flight2
passedFlight.id = 200
passedFlight.description = "second flight from virgin airlines"
}
yani,
modifyFlight(flight: flightA)
modifyFlight2(flight2: flightB)
Şimdi flightA'nın kimliğini ve açıklamasını yazdırırsak,
id = 200
description = "second flight of Virgin Airlines"
Burada, changeA yöntemine iletilen parametre aslında flightA nesnesinin (başvuru türü) bellek adresini gösterdiğinden FlightA'nın kimliğinin ve açıklamasının değiştiğini görebiliriz.
şimdi elde ettiğimiz FLightB örneğinin kimliğini ve açıklamasını yazdırırsak,
id = 100
description = "first ever flight of Virgin Airlines"
Burada, FlightF örneğinin değiştirilmediğini görebiliriz, çünkü changeFlight2 yönteminde gerçek Flight2 örneği başvuru (değer türü) yerine geçer.
Here we can see that the FlightB instance is not changed
Structs
var value type
ve Classes
varreference type
Aşağıdaki durumlarda bir value
tür kullanın :
Aşağıdaki durumlarda bir reference
tür kullanın :
Daha fazla bilgi Apple belgelerinde de bulunabilir
https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html
ek bilgi
Swift değer türleri yığın içinde tutulur. Bir işlemde, her iş parçacığının kendi yığın alanı vardır, dolayısıyla başka hiçbir iş parçacığı doğrudan değer türünüze erişemez. Bu nedenle, yarış koşulları, kilitler, kilitlenmeler veya ilgili iplik senkronizasyonu karmaşıklığı yoktur.
Değer türleri, her ikisi de pahalı işlemler olan dinamik bellek ayırma veya referans saymaya ihtiyaç duymaz. Aynı zamanda değer türlerine ilişkin yöntemler statik olarak gönderilir. Bunlar performans açısından değer türleri lehine büyük bir avantaj yaratır.
Hatırlatma olarak, Swift'in bir listesi
Değer türleri:
Referans türleri:
Soruyu değer türleri ve referans türleri açısından cevaplamak, bu Apple blog yazısından çok basit görünecektir:
Aşağıdaki durumlarda bir değer türü [örn. Struct, enum] kullanın:
- Örnek verileri == ile karşılaştırmak mantıklı
- Kopyaların bağımsız durumuna sahip olmasını istiyorsunuz
- Veriler kodda birden çok iş parçacığında kullanılacaktır
Aşağıdaki durumlarda bir referans türü [örn. Sınıf] kullanın:
- Örnek kimliğini === ile karşılaştırmak mantıklı
- Paylaşılan, değiştirilebilir durum oluşturmak istiyorsunuz
Bu makalede belirtildiği gibi, yazılabilir özelliği olmayan bir sınıf bir yapı ile aynı şekilde davranacaktır (bir ekleyeceğim): yapılar, güvenli uygulama modelleri için en iyisidir - modern uygulama mimarisinde giderek yaklaşan bir gereksinimdir.
Sınıflarda kalıtım elde edersiniz ve referans olarak aktarılırlar, yapıların kalıtım yoktur ve değere göre aktarılır.
Swift'te harika WWDC oturumları var, bu özel soru bunlardan birinde ayrıntılı olarak cevaplanıyor. Bunları izlediğinizden emin olun, çünkü Dil kılavuzundan veya iBook'dan çok daha hızlı hızlanmanızı sağlar.
Yapıların daha az işlevsellik sunduğunu söyleyemem.
Elbette, benlik, mutasyona uğrayan bir işlev dışında değişmezdir, ama hepsi bu kadar.
Kalıtım, her sınıfın soyut ya da nihai olması gerektiği eski iyi fikrine bağlı kaldığınız sürece iyi çalışır.
Soyut sınıfları protokol, son sınıfları da yapı olarak uygular.
Yapılarla ilgili güzel bir şey, paylaşılan mutable durumu oluşturmadan alanlarınızı değiştirilebilir hale getirebilmenizdir çünkü yazma üzerine kopya bununla ilgilenir :)
Bu nedenle, aşağıdaki örnekteki özelliklerin / alanların hepsi değiştirilebilir, bu da Java veya C # veya swift sınıflarında yapmayacağım .
"Örnek" işlevinde alt kısımda biraz kirli ve anlaşılır kullanım içeren örnek kalıtım yapısı:
protocol EventVisitor
{
func visit(event: TimeEvent)
func visit(event: StatusEvent)
}
protocol Event
{
var ts: Int64 { get set }
func accept(visitor: EventVisitor)
}
struct TimeEvent : Event
{
var ts: Int64
var time: Int64
func accept(visitor: EventVisitor)
{
visitor.visit(self)
}
}
protocol StatusEventVisitor
{
func visit(event: StatusLostStatusEvent)
func visit(event: StatusChangedStatusEvent)
}
protocol StatusEvent : Event
{
var deviceId: Int64 { get set }
func accept(visitor: StatusEventVisitor)
}
struct StatusLostStatusEvent : StatusEvent
{
var ts: Int64
var deviceId: Int64
var reason: String
func accept(visitor: EventVisitor)
{
visitor.visit(self)
}
func accept(visitor: StatusEventVisitor)
{
visitor.visit(self)
}
}
struct StatusChangedStatusEvent : StatusEvent
{
var ts: Int64
var deviceId: Int64
var newStatus: UInt32
var oldStatus: UInt32
func accept(visitor: EventVisitor)
{
visitor.visit(self)
}
func accept(visitor: StatusEventVisitor)
{
visitor.visit(self)
}
}
func readEvent(fd: Int) -> Event
{
return TimeEvent(ts: 123, time: 56789)
}
func example()
{
class Visitor : EventVisitor
{
var status: UInt32 = 3;
func visit(event: TimeEvent)
{
print("A time event: \(event)")
}
func visit(event: StatusEvent)
{
print("A status event: \(event)")
if let change = event as? StatusChangedStatusEvent
{
status = change.newStatus
}
}
}
let visitor = Visitor()
readEvent(1).accept(visitor)
print("status: \(visitor.status)")
}
Swift'te Protokol Odaklı Programlama olarak bilinen yeni bir programlama modeli tanıtıldı.
Yaratıcı Desen:
Hızlı olarak Struct, otomatik olarak klonlanan bir değer türüdür . Bu nedenle, prototip modelini ücretsiz olarak uygulamak için gerekli davranışı elde ederiz.
Oysa sınıfları otomatik olarak görev sırasında klonlanmış değildir referans tipi vardır. Prototip modelini uygulamak için sınıfların NSCopying
protokolü benimsemesi gerekir .
Sığ kopya yalnızca bu nesnelere işaret eden başvuruyu çoğaltırken derin kopya nesnenin başvurusunu çoğaltır.
Her referans türü için derin kopya uygulamak yorucu bir iş haline gelmiştir. Sınıflar daha fazla referans türü içeriyorsa, referans özelliklerinin her biri için prototip deseni uygulamalıyız. Ve sonra protokolü uygulayarak tüm nesne grafiğini kopyalamamız gerekiyor .NSCopying
class Contact{
var firstName:String
var lastName:String
var workAddress:Address // Reference type
}
class Address{
var street:String
...
}
Yapılar ve numaralandırmalar kullanarak , kopya mantığını uygulamak zorunda olmadığımız için kodumuzu basitleştirdik.
Birçok Kakao API'sı, sizi sınıf kullanmaya zorlayan NSObject alt sınıfları gerektirir. Ancak bunun dışında, bir yapı / numaralandırma değeri türü veya bir sınıf başvuru türü kullanıp kullanmayacağınıza karar vermek için Apple'ın Swift blogundaki aşağıdaki durumları kullanabilirsiniz.
Bu cevaplarda dikkat çekmeyen bir nokta, bir yapıya karşı bir sınıfı tutan bir değişkenin let
, nesnenin özelliklerinde değişikliklere izin verirken süre olabileceği, ancak bunu bir yapı ile yapamazsınız.
Değişkenin başka bir nesneyi hiç göstermesini istemiyorsanız, ancak yine de nesneyi değiştirmeniz gerekiyorsa, örneğin birbiri ardına güncellemek istediğiniz birçok örnek değişkeni olması durumunda bu yararlıdır. Bir yapı ise, bunu yapmak için değişkenin tamamen başka bir nesneye sıfırlanmasına izin vermelisiniz var
, çünkü Swift'teki sabit bir değer türü düzgün bir şekilde sıfır mutasyona izin verirken, referans türleri (sınıflar) bu şekilde davranmaz.
Yapı değer türleridir ve yığını içine depolayan hafızayı kolayca oluşturabilirsiniz.Yapıya kolayca erişilebilir ve işin kapsamından sonra yığının üstünden pop ile yığın hafızasından kolayca aktarılır. Öte yandan sınıf, yığın halinde depolanan ve bir sınıf nesnesinde yapılan değişikliklerin sıkı bir şekilde bağlandıkları ve referans tür olarak diğer nesneyi etkileyeceği bir referans türüdür. .
Yapının dezavantajları, miras alınamamasıdır.
Yapı ve sınıf kullanıcı tarafından tanımlanan veri türleridir
Varsayılan olarak, yapı halka açıkken sınıf özeldir
Sınıf kapsülleme prensibini uygular
Sınıftaki nesneler yığın belleğinde oluşturulur
Sınıf yeniden kullanılabilirlik için kullanılırken, yapı aynı yapıdaki verilerin gruplanması için kullanılır
Yapı veri üyeleri doğrudan başlatılamaz, ancak yapı dışından atanabilir
Sınıf veri üyeleri, daha az parametre yapıcısı tarafından doğrudan başlatılabilir ve parametrelenmiş kurucu tarafından atanabilir