iOSAppTemplates, iOS 18 için yazılmış 21 SwiftUI uygulama şablonundan oluşuyor: e-ticaretten
finansa, mesajlaşmadan seyahate. Yanında bir komut satırı aracı var: create-ios-app, bir
şablonu senin proje adınla kopyalıyor. 3.1.0 sürümü 14 Ekim 2026'da yayınlandı. Bu yazı
problemi, tasarım kararlarını, geçmişten gerçek bir hatayı, kullanımı ve sınırları anlatıyor.
İçindekiler
- Problem
- Tasarım kararları ve alternatifler
- Şablonlar bağımsız package; kök yalnız araç
- Davranış store'da, store da testli
- Üçüncü parti bağımlılık yok
- `@main` şablonda değil, host'ta
- Yeniden adlandırma: placeholder ya da sözdizimi ağacı değil, önek kuralı
- Clean Architecture şablonunda katmanlar ayrı target
- Gerçek bir hata: "Created" yazıyor ama proje derlenmiyor
- Kullanım
- Sınırlar
Problem
Bir şablon ancak ilk denemede derleniyorsa işe yarar. Pek çok başlangıç projesi çalışmadan
önce bir hesap, bir API anahtarı ya da üçüncü parti bir SDK istiyor. Pek çoğu da elle
kopyalanıp bul-değiştir ile yeniden adlandırılıyor; bu yöntemin hataları da çoğu zaman ancak
derlemede ortaya çıkıyor.
Bu repo da aynı sorunları yaşadı. 2 Ağustos 2025'te üç şablon paketiyle açıldı:
EcommerceApp, FitnessApp ve SocialMediaApp. Nisan 2026'da Templates/ altına 17 paket
daha eklendi, şablon sayısı 20'ye çıktı ve 26 Nisan'da v2.1.0 etiketlendi. Haziran 2026'da
kanıt betikleri silindi; aynı hafta içinde eski create-ios-app'e App Store metadata üretimi
ve etkileşimli mod eklendi, CI'daki şablon üretici kontrolü ise kırmızı kaldı. 3.0.0'ın
CHANGELOG'u Ekim'deki yeniden kurulumun bulduğu durumu yazıyor: Swift 6.4 ile kök paket
derlenmiyordu, çünkü 14 library product'ından üçü The Composable Architecture'a bağlıydı ve bu
kütüphane o sürümle derlenmiyor. Şablon testleri placeholder'dı. Üç şablonda tek test
XCTAssertTrue(true) idi, kalan on yedisinde test yalnız statik bir listenin üç elemanlı
olduğuna bakıyordu (commit 087eb7d). Eski create-ios-app, var olmayan paket sürümlerine
bağımlı projeler üretiyordu.
Ekim 2026'daki yeniden kurulum repoyu derlenen ve test edilen kısma daralttı. PR #22 (765
dosyada +13.881 / −81.774 satır) 3.0.0 oldu. PR #23 21. şablonu ekledi ve 3.1.0 oldu; ikisi de
14 Ekim'de.
Tasarım kararları ve alternatifler
Şablonlar bağımsız package; kök yalnız araç
3.0.0'dan önce kök paket, Templates/ altındaki uygulamaları tekrarlayan 14 eski library
product da taşıyordu; sekiz şablon paketi de Firebase, Kingfisher, Alamofire ya da Charts
çekiyordu. Şimdi her şablonun bağımlılıksız kendi Package.swift'i var: tek store'lu yirmi
şablonda tek library target ve tek test target, CleanArchitectureApp'te dörder tane. Kök
paket yalnız create-ios-app'i ve onun arkasındaki TemplateScaffold kütüphanesini içeriyor
ve aracın çalıştığı macOS 14'ü hedefliyor.
Bedeli şu: şablonlar remote package olarak yayınlanmıyor. README bunu açıkça söylüyor: her
şablon kopyalanıp değiştirilmek için var.
Davranış store'da, store da testli
Şablonlardan yirmisi bütün durumu ve aksiyonları bir @MainActor ObservableObject store'da
tutuyor; ekranlar ince kalıyor. Her store'un bir Swift Testing suite'i var ve şunları
kapsıyor: türetilen toplamlar, durum geçişleri, geçersiz girdi ve bilinmeyen id'ler için
guard'lar ve aşılmaması gereken sınırlar. "Kapsamak" ne demek, bir örnekle: e-ticaret
şablonundaki kargo testi önceden yalnız 150'nin üstündeki bir ara toplama bakıyordu; >='yi
> yapan bir değişiklik testten geçerdi. Eşik artık CommerceStore.shippingFee(forSubtotal:) arkasında ve test 149,99'u, tam
150'yi ve 150,01'i ayrı ayrı kontrol ediyor (commit bdf93a0).
Üçüncü parti bağımlılık yok
Şablonlar yalnız SwiftUI ve Foundation kullanıyor. Gerçek bir uygulamanın dış bir servise
bağlanacağı yerde şablon önüne bir protokol koyuyor. SocialMediaApp'te giriş bir
AuthService protokolünden geçiyor; birlikte gelen LocalAuthService hesapları bellekte
tutuyor ve bir demo hesabı sunuyor. 3.0.0'dan önce bu şablon FirebaseApp.configure()
çağırıyordu ve Firebase yapılandırma dosyası olmadan açılamıyordu.
`@main` şablonda değil, host'ta
@main tanımlayan bir library target bir uygulamaya link edilemiyor. Artık her şablon public
bir <Name>Shell scene sunuyor; küçük bir host dosyası yalnız <Name>Shell.main() çağırıyor.
Host projesi commit'lenmiş bir .xcodeproj değil, bir XcodeGen spec'i (App/project.yml):
okunabilir, diff'i anlamlı ve metin olarak yeniden adlandırılabiliyor. Bedeli, host projesini
açmak için XcodeGen gerekmesi. Examples/QuickStart ise XcodeGen'siz derlensin diye
commit'lenmiş bir proje taşıyor.
Yeniden adlandırma: placeholder ya da sözdizimi ağacı değil, önek kuralı
Bir şablonda değişmesi gereken her ad şablonun klasör adıyla başlıyor: EcommerceApp,
EcommerceAppShell, EcommerceAppTests, com.example.EcommerceApp. Böylece yeniden
adlandırma, dosya içeriklerine ve yol bileşenlerine uygulanan tek bir metin değişimine
dönüşüyor. IdentifierRenamer bir eşleşmeyi yalnız önündeki karakter harf, rakam ya da alt
çizgi değilse değiştiriyor; EcommerceAppTests MyShopTests oluyor, MyEcommerceApp olduğu
gibi kalıyor.
İki alternatif vardı. {{PROJECT_NAME}} gibi placeholder'lar kullanılsaydı şablon kendi başına
derlenmez, dolayısıyla test edilemezdi. Swift sözdizimi ağacına dayalı bir yeniden adlandırma
Swift kodu için daha kesin olurdu, ama project.yml'ı, Package.swift'teki string'leri ya da
bundle identifier'ı kapsamazdı. Metin değişiminin iki bedeli var: önekle başlamayan adlar
(ör. CommerceStore) aynı kalıyor ve değişim, zaten var olan bir adı üretebiliyor. İkincisi
gerçek bir hataya dönüştü.
Clean Architecture şablonunda katmanlar ayrı target
3.1.0'da eklenen CleanArchitectureApp, bir ekip dizini uygulamasını
CleanArchitectureAppDomain, CleanArchitectureAppData, CleanArchitectureAppPresentation
ve bir composition root'a bölüyor. Data ve Presentation yalnız Domain'e bağımlı; bu yüzden
"arayüz ağ koduna dokunmaz" kuralı bir code review maddesi değil, derleme hatası. İş kuralları
use case'lerde duruyor; örneğin son aktif admin'in rolü düşürülemiyor ve hesabı pasifleştirilemiyor.
Repository önce sunucuyu deniyor ve yalnız sunucuya ulaşılamazsa ya da 5xx dönerse kayıtlı
kopyaya düşüyor. 401 gibi diğer hatalar olduğu gibi iletiliyor.
Bu şablon ayrı duran ios-clean-architecture-template reposunun yerini aldı; o repo
arşivlendi. Taşınan yalnız fikir oldu: kod bu reponun kurallarıyla yeniden yazıldı. Dört test
target'ında 108 test ve biri accessibility audit olan üç UI testi var.
Gerçek bir hata: "Created" yazıyor ama proje derlenmiyor
create-ios-app yeniden yazıldıktan sonra testleri geçiyordu ve README'deki MyShop örneği
çalışıyordu. Aracı başka adlarla denemek bir sorunu ortaya çıkardı. Şu komut
"Created … (13 files)" yazıyordu:
swift
1new CommerceStore --template ecommerceÜrettiği proje ise derlenmiyordu. EcommerceApp.swift yeniden adlandırılınca
CommerceStore.swift oluyor ve gerçek CommerceStore sınıfının bulunduğu dosyanın üzerine
yazıyordu; modül adı da aynı sınıfla çakışıyordu. SocialMediaApp'te Models, Components,
FeedViewModel ve DataManager adlarında aynı sorun vardı.
PR #22'nin parçası olan b7356bb commit'indeki düzeltme işin sırasını değiştirdi.
Scaffolder artık şablonun tamamını önce belleğe okuyor ve hiçbir şey yazmadan önce yeniden
adlandırmanın üreteceği adları şablonda zaten var olan adlarla karşılaştırıyor: dosya ve klasör
adları ile Swift dosyalarında tanımlanan adlar (class, struct, enum, protocol, actor,
typealias, func, var, let, case). String ve yorumlardaki kelimeler sayılmıyor; yoksa
Acme gibi masum adlar da reddedilirdi. Hedef yollar ayrıca büyük/küçük harf duyarsız
karşılaştırılıyor, çünkü macOS'un varsayılan dosya sistemi Demo.swift ile demo.swift'i aynı
dosya sayıyor. Çakışma varsa araç ScaffoldError.nameConflict fırlatıyor ve hiçbir şey
oluşturmuyor. 3.1.0 tag'inde aynı komut şunu yazıyor:
swift
1Error: CommerceStore cannot be used with this template: renaming would produce names it already has (CommerceStore, CommerceStoreTests, Sources/CommerceStore/CommerceStore.swift). Choose another name.Testler tanımlı bir tiple çakışmayı, yalnız harf büyüklüğünde farklı bir yolu ve gerçek
şablonlardaki CommerceStore, Models ve FeedViewModel durumlarını kapsıyor. İlgili bir
düzeltme olan 509b060, import'tan sonra gelemeyen her Swift keyword'ünü (ör. guard ya da
public) proje adı olarak reddediyor; bu adlar derlenmeyen paketler üretiyordu.
Çıkan ders: dokümandaki örnekte geçen testler, kimsenin denemediği girdiler hakkında pek bir
şey söylemiyor.
Kullanım
Repoyu klonla, Templates/EcommerceApp gibi bir şablon klasörünü Xcode'da iOS 18 hedefli bir
uygulamaya local package olarak ekle ve @main içeren dosyanın içeriğini README'deki şu kodla
değiştir:
swift
1import EcommerceApp2 3@main4enum QuickStartApp {5 static func main() {6 EcommerceAppShell.main()7 }8}Bir test bu bloğu Examples/QuickStart/QuickStart/QuickStartApp.swift ile karşılaştırıyor;
README ile örnek birbirinden kopamıyor.
Yeniden adlandırılmış bir kopya için aracı klonun içinden çalıştır:
bash
1cd iOSAppTemplates2swift run create-ios-app list3swift run create-ios-app new MyShop --template ecommerce --output ~/DeveloperAynı mantık TemplateScaffold kütüphanesi olarak da kullanılabiliyor. README'deki bu örnek test
suite'i tarafından derlenip çalıştırılıyor:
swift
1import Foundation2import TemplateScaffold3 4func makeShop(templates: URL, output: URL) throws -> ScaffoldResult {5 guard let template = TemplateCatalog.template(named: "ecommerce") else {6 throw CocoaError(.fileNoSuchFile)7 }8 let name = try ProjectName("MyShop")9 return try Scaffolder(templatesDirectory: templates).scaffold(template, as: name, in: output)10}3.1.0 tag'inde swift test kütüphane ve araç için 6 suite'te 40 test koşuyor. CI'da şablonlar
310 test daha ekliyor: tek store'lu yirmi şablon için 202, CleanArchitectureApp için 108. Her
şablon iOS simülatöründe kendi job'ında koşuyor.
Sınırlar
- Şablonlar başlangıç noktası. Yirmisi bellekteki örnek veriyle çalışıyor. Çalışan bir tab
yapısı, navigasyon ve testli bir store veriyorlar; backend vermiyorlar.
- Remote package değil. Şablonlar local package olarak ekleniyor ya da kopyalanıyor;
create-ios-app reponun bir checkout'una ihtiyaç duyuyor.
- UI testi yalnız bir şablonda.
CleanArchitectureApp'in UI testleri var. Diğer yirmisinde
testler store'u kapsıyor; ekranlar docs/images'taki ekran görüntüleriyle kontrol ediliyor.
Snapshot testi yok.
- README yol haritasındaki açık işler: bazı durumlar hâlâ string olarak karşılaştırılıyor
(EcommerceApp'teki sipariş başlığı, MessagingApp'teki containment durumu,
AIAssistantApp'teki preset modu) ve çoğu şablon kodunu hâlâ tek bir <Name>.swift
dosyasında tutuyor. Paket henüz Swift Package Index'te listelenmiyor.
- Yeniden adlandırmanın kapsamı. Şablon adıyla başlamayan tipler adlarını koruyor;
tanımlar bir parser ile değil, regular expression ile bulunuyor.
- Yalnız örnek giriş.
LocalAuthServicehesapları demo için bellekte tutuyor; bir kimlik
doğrulama sistemi değil.
- Sürüm metinleri. 3.1.0 tag'inde
create-ios-app --versionhâlâ3.0.0yazıyor ve
README'deki sürüm rozeti v3.0.0 gösteriyordu. Rozet release'ten sonra PR #25 ile düzeltildi;
aynı PR, rozet CHANGELOG'un gerisinde kalınca kırılan bir CI kontrolü ekledi. CLI'daki sürüm
metni hâlâ elle güncelleniyor.
Kaynak kod: github.com/muhittincamdali/iOSAppTemplates

