İsteğe bağlı değeri nil olduktan sonra sayısal bir alanı düzenlenebilir tutmak için düzenlenebilir metni sayıdan ayrı saklayın. Önce ayrıştırmayı, devre dışı durumunu ve odağı kontrol edin; ardından uygulamanız açık bir kurtarma davranışı gerektiriyorsa dize tabanlı bir taslak kullanın.
Bu kılavuz, geliştirdiğiniz bir macOS uygulamasındaki sayısal bir alanı ele alıyor: sentetik bir Tile count değeri girme, alanı temizleme ve başka bir sayı girme. Amaç, sonraki düzenlemeye izin verirken anlamlı bir boş değeri korumaktır.
İsteğe bağlı sayı neden nil oldu?
Apple, isteğe bağlı değerler için özel bir SwiftUI başlatıcısı sağlar: TextField(value:format:prompt:label:). Belgelenen davranışı, biçim stili girdiyi ayrıştıramadığında bağlamayı nil olarak ayarlamaktır. Dolayısıyla dönüştürme başarısızlığı bu API’nin beklenen bir durumudur. Apple bu durumu alanın devre dışı kalması olarak tanımlamaz. Bu isteğe bağlı biçim stili başlatıcısı macOS 12 veya sonraki sürümleri gerektirir. Apple’ın isteğe bağlı değerler için TextField başlatıcısı
Uygulamanızın gerçekte hangi başlatıcıyı kullandığını kontrol edin. Eski formatter: başlatıcısının belgelenmiş başarısızlık davranışı farklıdır: dönüştürme başarısız olursa bağlı değeri değiştirmeden bırakır. formatter: yerine format: kullanmak bu sözleşmeyi değiştirir; bunu evrensel bir düzeltme olarak değil, davranışta bilinçli bir değişiklik olarak değerlendirin. Apple’ın formatter tabanlı TextField başlatıcısı
Temel tasarım sorunu, isteğe bağlı bir sayının tüm düzenleme durumlarını temsil edememesidir. Boş bir alan, kısmen girilmiş bir eksi işareti ve geçersiz bir dize kullanılabilir bir tam sayı içermeyebilir; ancak bunlar farklı metin taslaklarıdır. Bu nedenle ayrı bir taslak kullanmak yararlıdır: uygulama sayısal bir değeri ne zaman kabul edeceğine karar verirken alan, kişinin düzenlediği metni olduğu gibi tutabilir.
Alanı değiştirmeden önce hatanın kaynağını belirleyin
Kendi uygulama pencerenizde aşağıdaki adımları izleyin. Belirli bir macOS uygulama kusuru varsaymadan dönüştürme sorununu etkileşim sorunundan ayırır.
- Metnin gerçekten değişip değişmediğini kontrol edin. Alana tıklayın, içeriğini seçin ve
24yazın. Karakterler değişiyor ancak sayısal model değişmiyorsa dönüştürme ve işleme davranışını inceleyin. - Etkileşim koşullarını kontrol edin. Alanda ve kapsayıcılarında
.disabled(tileCount == nil)gibi koşullar arayın. Bu koşul, boş bir değerden kurtulmak için gereken düzenlemeyi engeller. - Alan hâlâ var mı kontrol edin. Görünümünüz düzenleyiciyi yalnızca bir
if letdalında oluşturuyorsa, değerinnilolarak ayarlanması düzenleyiciyi kaldırabilir. Taslağı ve düzenleyiciyi isteğe bağlı sayıdan bağımsız olarak kullanılabilir tutun. - Odağı ayrı olarak kontrol edin. Alan tıklamayı kabul ediyor ve ardından yazı yazılabiliyorsa uygun genel API üzerinden odağı geri yükleyin.
- Örneği küçültün. Özel bağlama dönüşümlerini ve model eşitlemesini geçici olarak kaldırın. Küçük bir görünümde
12değerinden boş değere, oradan da24değerine geçişi yeniden oluşturun.
Devre dışı bir üst öğe önemlidir: Apple, bir kapsayıcının .disabled(true) özelliğinin alt öğedeki .disabled(false) özelliğini geçersiz kıldığını belgeliyor. Yalnızca alanı tekrar tekrar etkinleştirmek yerine üst öğenin koşulunu düzeltin. Apple’ın disabled(_:) belgeleri
Özel bağlama ayarlayıcılarını da inceleyin. Mevcut sayı nil olduğunda erken dönen bir ayarlayıcı, yerine yeni bir sayı kabul edemez. Benzer şekilde, her başarısız dönüştürmeyi 0 olarak eşlemek, değerin bulunmaması ile gerçek bir sıfır arasındaki farkı ortadan kaldırır. Bunlar uygulama mantığıyla ilgili kararlardır; odağı değiştirmek bunları düzeltemez.
Düzenlenebilir taslağı saklayın ve sayıyı açıkça uygulayın
Dize tabanlı bir alan üç ayrı durumu denetlemenizi sağlar: mevcut metin, kabul edilen isteğe bağlı sayı ve bir doğrulama iletisi. Apple, dizeye bağlanan bir TextField öğesinin düzenleme sırasında bağlamasını sürekli güncellediğini belgeliyor. Bu nedenle tamamlanmamış girdiyi saklamak için uygundur. Apple’ın TextField genel bakışı
Aşağıdaki eksiksiz örnek şu politikayı kullanır: boş girdi nil anlamına gelir; geçerli bir 10 tabanlı tam sayı kabul edilen sayının yerini alır; geçersiz girdi görünür kalır ve kabul edilen sayıyı değiştirmez. Clear düğmesi her iki durumu da boşaltır ve başka bir sayı girilebilmesi için odak ister.
Xcode’da dağıtım hedefi macOS 12 veya üzeri olan bir macOS SwiftUI App projesi oluşturun. Oluşturulan uygulama ve içerik görünümü tanımlarını bu tek dosyayla değiştirin; hedefte yalnızca bir @main bildirimi bırakın. Örnek yalnızca kendi penceresini ve sentetik etiketleri kullanır. Araştırma ortamında Swift ve macOS SDK’sı bulunmadığından bu program incelendi, ancak derlenip çalıştırılmadı.
import SwiftUI
@main
struct NumericEditingDemoApp: App {
var body: some Scene {
WindowGroup {
NumericEditingView()
}
}
}
struct NumericEditingView: View {
@State private var tileCount: Int? = 12
@State private var draft = "12"
@State private var message: String? = nil
@FocusState private var fieldIsFocused: Bool
private var acceptedDescription: String {
if let value = tileCount {
return String(value)
}
return "None"
}
var body: some View {
VStack(alignment: .leading, spacing: 12) {
TextField("Tile count", text: $draft)
.textFieldStyle(.roundedBorder)
.focused($fieldIsFocused)
.onSubmit {
applyDraft()
}
HStack {
Button("Apply") {
applyDraft()
}
Button("Clear") {
tileCount = nil
draft = ""
message = nil
fieldIsFocused = true
}
Button("Edit") {
fieldIsFocused = true
}
}
Text("Accepted count: \(acceptedDescription)")
if let message = message {
Text(message)
.foregroundColor(.secondary)
}
}
.padding(20)
.frame(width: 380)
}
private func applyDraft() {
if draft.isEmpty {
tileCount = nil
message = nil
return
}
guard let parsed = Int(draft, radix: 10) else {
message = "Enter a whole number without spaces, or clear the field."
fieldIsFocused = true
return
}
tileCount = parsed
draft = String(parsed)
message = nil
}
}
Alan her zaman draft değerine bağlanır; bu nedenle tileCount değerini nil olarak ayarlamak düzenlenebilir metin durumunu kaldırmaz. Dönüştürme yalnızca kişi Apply düğmesine tıkladığında veya Return tuşuna bastığında yapılır. Geçersiz bir gönderimden sonra ileti, bir sonraki gönderime ya da Clear işlemine kadar görünür kalır; taslak düzeltme için kullanılabilir durumda kalır.
guard, başarısız bir dönüştürmenin kabul edilen sayının yerini almasını önler. Başarılı gönderimler yazımı String(parsed) üzerinden standartlaştırır: örneğin, +024 girmek 24 sonucunu verir. Bu, örneğe özgü açık bir politikadır. Gönderilen yazımı korumak yararlıysa bu standartlaştırma atamasını kaldırın.
Sayısal gösterim kurallarını bilinçli seçin
Bu örnek işaretli, gruplandırılmamış 10 tabanlı tam sayıları kabul eder. Boşlukları, ondalık kesirleri ve basamak gruplama ayraçlarını reddeder. Swift, Int(_:radix:) öğesinin geçersiz girdi veya tam sayı türünün temsil edemediği bir değer için nil döndürdüğünü belgeliyor; bu nedenle izin verilen aralığı aşan yapıştırılmış bir sayı da doğrulama yolunu izler. Swift’in Int dize başlatıcısı
Yerelleştirilmiş sayısal gösterim gerektiren bir alan için aynı taslak ve uygulama yapısını koruyun, ancak dönüştürmeyi uygun bir Foundation ayrıştırma stratejisiyle değiştirin. Bir ParseableFormatStyle, parseStrategy özelliğini sunar; stratejinin parse(_:) yöntemi dönüştürmeyi yapar ve hata verebilir. Taslağı koruyarak başarısızlığı ele alın. Birbiriyle uyumlu biçimlendirme ve ayrıştırma kuralları seçin, ardından amaçlanan yerel ayarlarda test edin. Apple’ın ParseableFormatStyle belgeleri, Apple’ın ParseStrategy belgeleri
Uygulamanızın başka bir bölümü kabul edilen sayıyı değiştirebiliyorsa, bu güncellemenin tamamlanmamış bir taslağı nasıl etkileyeceğini belirleyin. Örneğin, bilinçli bir Load value işlemi her iki durumu da güncelleyebilir. Düzenleme sırasında taslağı kabul edilen sayıdan sürekli yeniden oluşturmayın; bu, bu tasarımın koruduğu tamamlanmamış metni siler.
Odağı SwiftUI veya AppKit üzerinden geri yükleyin
SwiftUI’da örnekte olduğu gibi düzenleyiciye .focused($fieldIsFocused) ekleyin ve yerel bir işlemden fieldIsFocused = true ayarlayın. Apple, bir odak durumu değerinin atanmasının ilişkili görünüme odağı taşıdığını belgeliyor. Ayrı alanlara farklı odak bağlamaları verin; birden fazla alana aynı odak değerini atamak belirsizlik yaratır. Apple’ın FocusState belgeleri
Odak, düzenlemenin nereye gideceğini belirler. Ayrıştırıcıyı değiştirmez, devre dışı bir üst öğeyi yeniden etkinleştirmez veya koşullu görünüm mantığının kaldırdığı bir düzenleyiciyi yeniden oluşturmaz. Odak kurtarma eklemeden önce bu koşulları çözün.
Uygulamanızın sahip olduğu bir AppKit alanı için NSTextField.isEditable özelliğini inceleyin. Apple bu özelliği, kullanıcının alanın değerini düzenleyip düzenleyemeyeceğini denetleyen özellik olarak tanımlar. Kendi kodunuz yanlışlıkla false yaptıysa, amaçlanan uygulama kısıtlamalarını koruyarak true olarak geri ayarlayın. Apple’ın NSTextField.isEditable belgeleri
AppKit odağını açıkça taşırken acceptsFirstResponder değerini kontrol edin ve sahibi olan pencerenin makeFirstResponder(_:) yöntemini çağırın. Sonucunu dikkatle değerlendirmek gerekir: false, mevcut yanıtlayıcının ilk yanıtlayıcı olma durumundan vazgeçmeyi reddettiği anlamına gelebilir; önerilen yanıtlayıcı reddettiğinde ve pencere ilk yanıtlayıcı olduğunda da true görülebilir. Ortaya çıkan düzenleme durumunu doğrulayın. Değiştirmek üzere alanın tümünü seçmek için belgelenmiş işlem selectText(_:) yöntemidir; alan bir pencerenin görünüm hiyerarşisine katılmadan önce etkisi olmaz. Apple’ın makeFirstResponder(_:) belgeleri, Apple’ın selectText(_:) belgeleri
Alan düzenleyicisinin yaşam döngüsüne uyun
AppKit’in currentEditor() yöntemi, denetimin mevcut alan düzenleyicisini veya yoksa nil değerini döndürür. Apple bu düzenleyiciyi, bir penceredeki denetimler arasında paylaşılan ve gerektiğinde oluşturulan bir NSTextView olarak tanımlar. Bu nedenle etkin bir düzenleme oturumu dışındaki bir nil düzenleyici, sayısal girdi işlevinin bozuk olduğunu göstermez. Apple’ın currentEditor() belgeleri
Metin sistemi düzeyinde bir alan düzenleyicisi, Tab, Shift-Tab ve Return tuşlarını düzenlemeyi bitirme ve muhtemelen ilk yanıtlayıcıyı değiştirme sinyalleri olarak ele alır. isFieldEditor değerini sayısal dönüştürme düzeltmesi olarak değiştirmeyin: bu özellik, isteğe bağlı sayıların ayrıştırılmasını değil düzenleme davranışını yönetir. Bu AppKit ve TextKit kontrollerini uygulamanızın sahip olduğu denetimlerle sınırlı tutun. Apple’ın NSTextView.isFieldEditor belgeleri
Temizleme ve yeniden girişin ikisinin de çalıştığını doğrulayın
Uygulamanızın desteklediği her macOS sürümünde, eksiksiz örneğe karşı bu elle uygulanan adımları yürütün. Bunlar, bildirilen test sonuçları değil, örneğin mantığından çıkarılan beklenen sonuçlardır.
| İşlem | Beklenen kabul edilen değer | Beklenen düzenleme davranışı |
|---|---|---|
| Başlatma | 12 |
Taslak 12 içerir |
Clear düğmesine tıklama |
nil, None olarak görüntülenir |
Taslak boştur; odak istenir |
24 yazıp Apply düğmesine tıklama |
24 |
Taslak 24 içerir |
- ile değiştirip Return tuşuna basma |
Önceki kabul edilen değer | Taslak - olarak kalır; ileti görünür |
-8 ile değiştirip Return tuşuna basma |
-8 |
İleti temizlenir |
0 girip Apply düğmesine tıklama |
0 |
Sıfır, değer yokluğundan ayrı kalır |
2.5 girip Apply düğmesine tıklama |
Önceki kabul edilen değer | Kesirli metin düzeltme için kalır |
Alanı boşaltıp Apply düğmesine tıklama |
nil |
Alan başka bir düzenleme için kullanılabilir kalır |
Ayrıca Int.max değerinden büyük bir tam sayıyı yapıştırmayı, alandan ayrılıp geri dönmeyi ve alanı art arda birkaç kez temizlemeyi deneyin. Entegre bir uygulamada modeli başka yerde değiştiren tüm işlemleri de ekleyin. Bu kontroller dönüştürme başarısızlığını, odak kurtarmayı ve taslak eşitlemesini ayrı ayrı sınar.
Yararlı kurtarma koşulu somuttur: kabul edilen sayı nil olduktan sonra düzenleyici görünür ve etkileşimli kalır; daha sonra yapılan geçerli bir gönderim yeni bir sayı sağlar. Taslağı bağımsız tutmak, SwiftUI’ın arka plandaki denetimlerinde belgelenmemiş değişikliklere bağlı kalmadan bu davranışı açık hale getirir.
Kaynaklar
- init(value:format:prompt:label:) — Apple
- init(_:value:formatter:) — Apple
- TextField — Apple
- disabled(_:) — Apple
- init(_:radix:) — Apple, Swift Standart Kitaplığı
- ParseableFormatStyle — Apple
- ParseStrategy — Apple
- FocusState — Apple
- NSTextField.isEditable — Apple
- makeFirstResponder(_:) — Apple
- selectText(_:) — Apple
- currentEditor() — Apple
- NSTextView.isFieldEditor — Apple