İlişkili değerleri yok sayarak ardışık Swift enum durumlarını bastırmak için ayrı bir durum anahtarını karşılaştırın ve her dizideki ilk tam değeri koruyun. Bu yerel Mac örneği sıralamayı korur ve bir durumun başka bir durumdan sonra yeniden görünmesine izin verir.

Yinelenen olarak tam olarak neyin sayılacağını tanımlayın

Bir masaüstü grafik önizlemesinin şu adımlardan oluşan sentetik bir dizi ürettiğini varsayalım: boşta, adı belirtilmiş bir şekli çizme ve adı belirtilmiş bir önizlemeyi gösterme. Durum geçişlerinin kısa bir listesini istiyorsunuz. Şekil adları farklı olsa bile ardışık iki çizim adımı yinelenen sayılır.

Swift enum'ları her durum için farklı ilişkili değerler taşıyabilir. Bu değerler enum değerinin parçasıdır; dolayısıyla onları yok saymayı seçmek için açık bir karşılaştırma kuralı gerekir. Swift dil kılavuzu bu ayrımı Enumerations bölümünde açıklar.

Bu görev için şu sözleşmeyi kullanın:

  • İlk girdi değerini koruyun.
  • Sonraki değerlerden, durumu önceki dizinin durumuyla eşleşenleri bastırın.
  • Korunan her öğenin ilişkili değerinin tamamını saklayın.
  • Farklı bir durumdan sonra geldiğinde aynı duruma yeniden izin verin.
  • Girdi sırasını koruyun; boş bir girdi boş bir sonuç üretir.

Aşağıda örnek bir girdi için amaçlanan davranış gösterilmiştir. Tüm adlar sentetiktir.

Girdi değeri Karar Gerekçe
.idle Koru İlk değer
.drawing("Circle") Koru Durum değişti
.drawing("Square") Bastır Hâlâ çizim yapılıyor
.ready("Preview A") Koru Durum değişti
.ready("Preview B") Bastır Hâlâ hazır
.drawing("Triangle") Koru Hazır durumundan sonra çizim geliyor
.idle Koru Durum değişti
.idle Bastır Hâlâ boşta

Böylece korunan çizim değerleri \"Circle\" ve \"Triangle\" olur. \"Square\" yükü bilerek dışarıda bırakılır. Masaüstü görünümünün güncellenen tüm şekil adlarını göstermesi gerekiyorsa bu sözleşme görünümün ihtiyaç duyduğu değişiklikleri atar; bu tüketici için yüke duyarlı bir karşılaştırma seçin.

Mac'inizde eksiksiz bir yerel Swift örneği çalıştırın

Çalışan bir Swift geliştirme ortamına sahip bir Mac kullanın. Swift.org, Apple platformu geliştirme için Xcode'u önerir ve Swift Package Manager ile komut satırında çalıştırılabilir dosya oluşturma iş akışını belgeler. Araçları hazırlamanız gerekiyorsa Install Swift — macOS yönergelerini izleyin.

Terminal'de yeni bir çalışma dizininde küçük bir çalıştırılabilir paket oluşturun:

mkdir EnumCaseDemo
cd EnumCaseDemo
swift package init --name EnumCaseDemo --type executable

Oluşturulan çalıştırılabilir kaynak dosyasının içeriğini aşağıdaki eksiksiz programla değiştirin. Program Swift standart kitaplık türlerini kullanır; içe aktarma veya paket bağımlılığı gerektirmez. Girdisi ve çıktısı bellekte kalır; korunan sentetik adımları yazdırır.

enum PreviewStep: Equatable {
    case idle
    case drawing(String)
    case ready(String)

    enum Kind: Equatable {
        case idle
        case drawing
        case ready
    }

    var kind: Kind {
        switch self {
        case .idle:
            return .idle
        case .drawing(_):
            return .drawing
        case .ready(_):
            return .ready
        }
    }

    var label: String {
        switch self {
        case .idle:
            return "idle"
        case .drawing(let shape):
            return "drawing: \(shape)"
        case .ready(let name):
            return "ready: \(name)"
        }
    }
}

func suppressConsecutiveCases(
    _ steps: [PreviewStep]
) -> [PreviewStep] {
    var result: [PreviewStep] = []
    var previousKind: PreviewStep.Kind? = nil

    for step in steps {
        let currentKind = step.kind
        if let previous = previousKind,
           previous == currentKind {
            continue
        }

        result.append(step)
        previousKind = currentKind
    }

    return result
}

let input: [PreviewStep] = [
    .idle,
    .drawing("Circle"),
    .drawing("Square"),
    .ready("Preview A"),
    .ready("Preview B"),
    .drawing("Triangle"),
    .idle,
    .idle
]

let expected: [PreviewStep] = [
    .idle,
    .drawing("Circle"),
    .ready("Preview A"),
    .drawing("Triangle"),
    .idle
]

let output = suppressConsecutiveCases(input)

precondition(output == expected)
precondition(suppressConsecutiveCases([]).isEmpty)
precondition(
    suppressConsecutiveCases([
        .drawing("Circle"), .drawing("Square")
    ]) == [.drawing("Circle")]
)
precondition(
    suppressConsecutiveCases([
        .idle, .drawing("Circle"), .idle
    ]) == [.idle, .drawing("Circle"), .idle]
)

for step in output {
    print(step.label)
}

Paketi kendi dizininden çalıştırın:

swift run EnumCaseDemo

Derleme mesajlarından sonra beklenen program çıktısı şöyledir:

idle
drawing: Circle
ready: Preview A
drawing: Triangle
idle

Bu örnekler, alınan belgelere göre incelendi; araştırma ortamında Swift çalıştırılabilir dosyası bulunmadığından burada yürütülmedi. Dahil edilen önkoşul kontrolleri beklenen korunan yükleri, boş girdiyi, art arda gelen farklı yükleri ve bir geçişten sonra durumun yeniden görünmesini denetler.

Ayrı bir durum anahtarı neden işe yarar

kind özelliği, her tam enum değerini yük taşımayan küçük bir anahtara dönüştürür. Hem .drawing("Circle") hem de .drawing("Square") .drawing anahtarını üretir. Filtreleme işlevi bu anahtarları karşılaştırırken özgün step değerini ekler; böylece korunan ilişkili değerler olduğu gibi kalır.

İşlevin hatırlaması gereken tek bir anahtar vardır. Başlangıçta previousKind, nil değeridir ve bu, ilk öğenin geçmesine izin verir. Bir öğeyi koruduktan sonra onun türünü hatırlar. Bastırılan öğeler aynı türde olduğundan, onlar için hatırlanan anahtarı güncellemek sonucu değiştirmez.

Bu uygulama girdiyi bir kez dolaşır. Bu sabit enum ve sabit boyutlu anahtarları için, sonraki her öğede bir durum anahtarı karşılaştırması yapar ve döndürülen dizi dışında sabit miktarda yardımcı durum kullanır. Swift'in Sequence belgeleri, sıralı yinelemeyi ve olağan doğrusal dolaşım modelini açıklar.

Tam PreviewStep türü ayrıca Equatable uyumludur; bu sayede önkoşullar, korunan dizeler de dahil olmak üzere sonuçların tamamını doğrulayabilir. İlişkili değerleri Equatable uyumlu olan uygun enum'larda Swift eşitliğin sentezlenmesini destekler; Protocols bölümüne bakın. Durum karşılaştırmasını Kind içinde tutmak, program genelinde eşitliği yeniden tanımlamadan bu filtreleme işlemine açık bir kural verir.

kind içindeki kapsamlı switch yapısı da yararlı bir bakım kontrol noktası sunar. Yeni bir durum eklediğinizde ona karşılık gelen anahtarı ve eşlemeyi de ekleyin. Yeni bir durumu yanlışlıkla mevcut bir durumla gruplandırabilecek genel bir eşlemeden kaçının. Swift, enum'lar üzerinde kapsamlı switch kullanımını Enumerations bölümünde belgeler.

Combine ile aynı karşılaştırmayı kullanın

Mac kodunuz zaten bir Combine publisher kullanıyorsa Apple, özel bir karşılaştırma için removeDuplicates(by:) sağlar. Yüklemi, ikinci değerin yinelenen sayılması gerektiğinde true döndürür. Apple, istenen karşılaştırma çıktı türünün olağan eşitliğinden farklı olduğunda bu operatörün kullanımını açıkça destekler. macOS 10.15 ve sonraki sürümlerde kullanılabilir. Bkz. removeDuplicates(by:).

Aşağıdaki kod bağımsız bir program değil, bir uzantı parçasıdır. Combine'ın kullanılabildiği bir Mac'te bunu yukarıdaki eksiksiz örneğe ekleyin. Mevcut PreviewStep tanımını ve input dizisini yeniden kullanır:

import Combine

let subscription = input.publisher
    .removeDuplicates { previous, current in
        previous.kind == current.kind
    }
    .sink { step in
        print("Combine: \(step.label)")
    }

Bu, aynı beş korunan adımı \"Combine: \" önekiyle yazdırır. Yüklem durum anahtarlarını karşılaştırır ve publisher, korunan özgün enum değerlerini aktarır. Apple'ın kendi operatör örneği de bir özelliği karşılaştırıp diğerini yok sayarak aynı ilkeyi izler. removeDuplicates(by:)

Döndürülen aboneliği, gereken abonelik süresi boyunca canlı tutun. Apple, sink(receiveValue:) tarafından döndürülen değerin serbest bırakılmasının aboneliği sonlandırdığını belgeler. Bu aşırı yük, Apple'ın dizi publisher örneklerinde olduğu gibi hata türü Never olan publisher'lar için geçerlidir. sink(receiveValue:)

Kodu uyarlamadan önce sınır durumlarını denetleyin

Elinizde zaten sonlu bir yerel liste varsa dizi işlevini kullanın. Değerler zaten bir publisher üzerinden geliyorsa Combine operatörünü kullanın. Buradaki iki sürüm de aynı durum geçişi sözleşmesini ifade eder.

Gereksinim Uygun karşılaştırma veya yaklaşım
Her durum dizisindeki ilk tam değeri korumak Gösterildiği gibi kind değerini karşılaştırın
İlişkili dizelerdeki değişiklikleri korumak Olağan eşitliği kullanarak tam değerleri karşılaştırın
Her dizideki son tam değeri korumak Bekleyen bir değeri arabelleğe alın; durum geçişinde ve sonda arabelleği boşaltın
Başka bir durumdan sonra geri dönen durumu korumak Genel bir daha önce görülmüş durum listesi tutmak yerine ardışık dizileri karşılaştırın
Ayrı dizileri birbirinden bağımsız filtrelemek İşlevi ayrı ayrı çağırın; her çağrı karşılaştırma durumunu boş başlatır

Son yükü korumak farklı bir algoritma gerektirir; çünkü bu program ilk değeri hemen ekler. Benzer şekilde, tek bir mantıksal diziyi ayrı dizilere bölmek karşılaştırma durumunu sıfırlar: bir grubun sonundaki çizim değeri ile sonraki grubun başındaki başka bir çizim değeri ayrı çağrılarda ikisi de korunur. Grupların tek bir dizi gibi davranması gerekiyorsa önceki anahtarı grup sınırları boyunca koruyun.

Foundation, Apple platformu uygulamaları için koleksiyonlar ve diğer temel işlevleri sağlar; ancak bu hesaplama tümüyle Swift türleriyle uygulanır. Publisher sürümü özellikle Combine gerektirir; import Foundation eklemek bu operatörü içe aktarmaz. Apple, bu çerçeveleri Foundation ve removeDuplicates(by:) bölümlerinde ayrı ayrı belgeler.

Eşzamanlı dizi işlevi de eşzamanlılık mekanizması gerektirmez: karşılaştırma durumu her çağrıya aittir. Daha sonra paylaşılan masaüstü sunum durumu eklerseniz bu durumun yalıtımını ayrıca tanımlayın. Apple, MainActor'ı yürütücüsü ana dispatch kuyruğuna eşdeğer olan tekil bir aktör olarak belgeler; yinelenenleri bastırma işlemi kendi başına bir aktör seçmez. MainActor

Burada gösterilen yerel görev için belirleyici seçim, bir dizide hangi yükün korunacağıdır. İlk yükü seçtikten sonra ayrı bir durum anahtarıyla davranışı kolayca okuyup doğrulayabilirsiniz: durum geçişinde özgün değeri koruyun, eşleşen ardışık anahtarları bastırın ve geri dönen durumların geçmesine izin verin.

Kaynaklar