iOS teknik mülakatları yalnızca Swift sözdizimini ezberlemekten ibaret değildir. İyi bir mülakat; gerçek bir iOS uygulamasını tasarlayıp geliştirebildiğinizi, production problemlerini araştırabildiğinizi, test yazabildiğinizi ve uzun vadeli teknik kararlar verebildiğinizi anlamaya çalışır.
Mülakat yapan kişi bir teknoloji adının ne yaptığını bilip bilmediğiniz kadar, o teknolojiyi ne zaman seçtiğinizi, hangi problemi çözdüğünüzü, hangi alternatifleri değerlendirdiğinizi, değişikliği nasıl doğruladığınızı ve sonuçtan sonra ne öğrendiğinizi de duymak ister.
Bu rehber; Swift, Swift Concurrency, SwiftUI, UIKit, mimari, networking, persistence, testing, performance ve production mühendisliği başlıklarıyla iOS teknik mülakatına hazırlanmanıza yardımcı olur.
Daha derin bir production proje yapısı incelemesi için Modern Bir iOS Projesi Nasıl Yapılandırılmalı? makalesine de bakabilirsiniz.
iOS Mülakatları Gerçekte Neyi Ölçer?
Tipik bir iOS mülakatı aynı anda birkaç mühendislik boyutunu değerlendirir. Swift ve concurrency sorularının yanında mimari, debugging, ürün düşüncesi, performans, test disiplini, iletişim ve sahiplenme de ölçülür.
Örneğin yalnızca “async/await nedir?” sorusuyla karşılaşmayabilirsiniz. Bunun yerine, üç network request’i başlayan bir ekranın kullanıcı başka sayfaya gittiğinde cancellation davranışını nasıl yöneteceğiniz sorulabilir.
Benzer şekilde “MVVM nedir?” yerine 1.500 satırlık bir ViewModel’ın networking, persistence, formatting, navigation ve analytics sorumluluklarını nasıl ayıracağınız konuşulabilir. Bu fark, mülakatın ezberlenmiş tanımlardan çok mühendislik muhakemesini ölçtüğünü gösterir.
Hazırlanmanız Gereken Alanlar
Swift temelleri: value ve reference semantics, protocol, generic, optional, closure, ARC, error handling ve access control.
Swift Concurrency: async/await, Task, structured concurrency, cancellation, actor, @MainActor, Sendable ve data race önleme.
SwiftUI: state yönetimi, @State, @Binding, Observation, view identity, rendering, navigation, reusable component’ler ve UIKit birlikte çalışabilirliği.
UIKit: çünkü birçok production uygulaması hâlâ büyük ve kritik UIKit ekranlarına sahiptir.
Mimari: MVVM, Clean Architecture, coordinator, dependency injection, repository, modularization ve feature sınırları.
Networking ve persistence: URLSession, authentication, retry, pagination, caching, error handling, idempotency, SwiftData, Core Data, Keychain, migration ve offline-first tasarım.
Testing ve performance: Swift Testing, XCTest, unit test, integration test, UI test, dependency injection, Instruments, memory leak, retain cycle, startup ve scrolling performansı.
Production mühendisliği: crash reporting, logging, feature flag, release monitoring, App Store deployment, background execution ve lokal ortamda kolayca reproduce edilemeyen problemleri araştırma.
Cevapları Ders Kitabı Gibi Vermeyin
Teknik mülakatlardaki en büyük hatalardan biri doğru ama tamamen soyut cevaplar vermektir.
MVVM, View ile business logic arasında ViewModel kullanarak ayrım yapar.
Bu tanım doğru olsa da gerçekten MVVM kullanıp kullanamadığınızı göstermez. Daha güçlü bir cevap, yaşanmış veya gerçekçi bir proje bağlamını açıklar:
Bir medya uygulamasında ViewController playback state, networking, persistence ve UI update’lerinden sorumluydu. Bu yapı ekranı test etmeyi zorlaştırıyor ve lifecycle problemleri oluşturuyordu. Kalıcı ekran state’ini ViewModel’a taşıdım, remote ve local data için repository sınırları ekledim ve view’ı state render edip kullanıcı aksiyonlarını iletecek şekilde sadeleştirdim. Böylece business logic’in büyük bölümünü UI’ı çalıştırmadan unit test edebildim.
Doğal bir senior cevap akışı şu şekilde olabilir:
Teknik cevap → Proje bağlamı → Problem → Karar ve uygulama → Doğrulama → Sonuç
Mülakatta “Situation, Task, Action, Result” başlıklarını ayrı ayrı söylemeniz gerekmez. Cevap, doğal bir mühendislik konuşması gibi ilerlemelidir.
30 iOS Teknik Mülakat Sorusu ve Gerçekçi Örnek Cevaplar
Güçlü iOS mülakat cevapları iki şeyi birlikte gösterir: net bir teknik açıklama ve bu kavramı gerçek bir projede uyguladığınıza dair kanıt.
Aşağıdaki örnekler açıkça “Situation, Task, Action, Result” demeden doğal bir STAR akışını izler. Her cevap önce teknik soruyu yanıtlar, sonra gerçekçi bir proje senaryosuna geçer:
Teknik cevap → Proje bağlamı → Problem → Karar ve uygulama → Doğrulama → Sonuç
Bu cevapları kelimesi kelimesine ezberlemeyin. Kendi deneyiminizde iOS kavramlarını gerçek mühendislik problemleriyle nasıl ilişkilendireceğinizi öğrenmek için kullanın.
1. Yakın zamanda çalıştığınız bir iOS projesini anlatır mısınız?
İyi bir cevap ürünü, sorumluluklarınızı, kullandığınız teknolojileri ve kişisel olarak çözdüğünüz bir mühendislik problemini kısa sürede ortaya koymalıdır.
Swift, SwiftUI, AVFoundation ve native işlevler için Objective-C++ bridge kullanan bir medya işleme uygulamasında çalıştım. Kullanıcılar medya import ediyor, işleme ayarlarını uyguluyor, sonucu preview ediyor ve export ediyordu.
Zorluklardan biri UI, playback state ve processing configuration arasındaki tutarlılığı korumaktı. Başlangıçta bazı state’ler SwiftUI view’larında, bazıları ise medya işleme katmanında tutuluyordu. Bu durum preset değiştirme ve A/B karşılaştırması gibi özellikleri zorlaştırıyordu.
Kalıcı editor state’ini ayrı bir ViewModel’a taşıdım ve processing engine’i ayrı bir service sınırının arkasında tuttum. SwiftUI ağırlıklı olarak state’i render edip kullanıcı aksiyonlarını iletti.
Akışı tekrarlı medya import’ları, preset değişimleri, background/foreground geçişleri ve export işlemleriyle test ettim. Sonuç daha net bir ownership modeli ve UI değişikliklerinin medya işleme kodunu etkilemediği daha kolay bir feature geliştirme süreci oldu.
2. Swift’te struct ve class arasındaki fark nedir?
struct value semantics kullanır; class ise reference semantics ve identity taşır. Shared identity gerekmiyorsa model ve UI state için genellikle struct ile başlamayı tercih ederim.
Bir SwiftUI uygulamasında editor configuration’ı volume, EQ ayarları, stereo width ve preset bilgilerini taşıyan bir struct olarak modelledim. Önceki versiyonda mutable shared object’ler kullanıldığı için hangi component’in mevcut configuration’ı değiştirdiğini anlamak zordu.
Editor state’ini value type’lara taşımak her state geçişini görünür hâle getirdi. Kullanıcı yeni bir preset seçtiğinde, değişmemesi gereken değerleri koruyan yeni bir state oluşturabildim. Buna karşılık uzun ömürlü ve dış kaynakları yöneten audio-processing engine class olarak kaldı.
Buradaki karar struct’ların her zaman daha iyi olması değil, nesnenin bir value mı yoksa yaşam süresi olan bir identity mi temsil ettiğini anlamaktır.
3. Bir iOS uygulamasında memory leak’i nasıl araştırırsınız?
Önce bir nesnenin gerçekten hayatta kaldığını doğrular, sonra Xcode Memory Graph ve Instruments ile ownership chain’i incelerim.
Bir medya uygulamasında editor ekranı her açılıp kapandığında memory kullanımının arttığını varsayalım. İlk olarak ekranın ViewModel’ının veya medya nesnelerinin deallocate edilip edilmediğini kontrol ederim. Geçici bir
deinitkontrolü ekler, ardından Memory Graph ile nesneyi kimin tuttuğunu bulurum.Bu tip bir feature’da uzun ömürlü player veya service’in ViewModel’ı strong capture eden bir callback saklaması olası bir nedendir. Her yere
[weak self]eklemek yerine ownership ilişkisini düzeltir, navigation ve media-loading akışını tekrar çalıştırırken allocation’ları izlerim.Beklenen sonuç editor ve medya kaynaklarının ekrandan ayrıldıktan sonra serbest kalması ve memory kullanımının kararlı bir seviyeye dönmesidir.
4. weak ve unowned ne zaman kullanılır?
weak, referans verilen nesnenin bu referansı tutan nesneden önce yok olabileceği durumlarda kullanılır. unowned ise yaşam süresi ilişkisinin kesin olduğu durumlarda uygundur.
Uzun ömürlü bir processing service’in progress bilgisini ekrana ilettiği bir medya uygulamasını düşünelim. Processing devam ederken ekran kapanabilir; callback’in ekranı strong tutmasını istemem. Bu nedenle weak referans kullanır ve UI artık yoksa callback’i güvenle yok sayarım.
unownedancak referans verilen nesnenin holder’dan daha uzun yaşayacağını garanti edebiliyorsam uygundur. Bu varsayım ileride değişirsenilyerine crash oluşacağı için unowned kullanımında daha temkinliyim.
5. ARC nasıl çalışır?
ARC, class instance’larının strong referanslarını takip eder ve son strong referans ortadan kalktığında nesneyi deallocate eder. Production’daki asıl problem çoğunlukla ARC değil, retain cycle’dır.
Media playback içeren uygulamalarda player, timer, notification observer, closure, subscription ve asynchronous callback’lerin yaşam sürelerine özellikle dikkat ederim. Örneğin playback service bir progress callback’i tutuyor ve callback ViewModel’ı strong capture ediyorsa iki nesne birbirini hayatta tutabilir.
Ownership chain’i inceler, cycle’ı doğru architectural boundary’de kırar ve Memory Graph ile tekrarlı navigation testi üzerinden düzeltmeyi doğrularım. ARC’ı compiler’ın tamamen çözdüğü bir ayrıntıdan çok ownership tasarımı problemi olarak görürüm.
6. Swift Concurrency ve async/await ne gibi avantajlar sağlar?
async/await asynchronous kodu daha okunabilir hâle getirir; daha büyük avantajları ise structured lifetime, cancellation ve daha net error propagation’dır.
Bir uygulamada editor kullanılabilir hâle gelmeden önce medya metadata’sı ve proje bilgilerinin yüklenmesi gerekiyordu. Callback tabanlı yapı loading state ve error’ların birkaç completion handler’dan güncellenmesine neden oluyordu. Kullanıcı ekrandan ayrıldıktan sonra callback’in gelmesi de mümkündü.
Akışı async function’lara taşıdım ve task yaşamını bu işi isteyen feature’a bağladım. Ekran kapandığında task cancel edilebildi. Başarılı yükleme, network failure, cancellation ve hızlı navigation senaryolarını test ettim. Sonuç daha basit bir lifecycle ve stale asynchronous work’ün UI state’i etkileme ihtimalinin azalması oldu.
7. Structured concurrency nedir?
Structured concurrency, asynchronous operasyonların tanımlı bir parent task’a ait olmasıdır.
Editor ekranının tamamlanması için remote project metadata ve local media bilgilerinin gerektiği bir projeyi düşünelim. Bu iki operasyon bağımsız olduğu için
async letile paralel çalıştırılabilir; ancak ikisi de aynı parent task’ın child’ı olarak kalır.Kullanıcı projeyi kapattığında parent task’ın cancellation’ı artık gerekmeyen child işleri de durdurur. İşi bağımsız task’lar olarak başlatıp hangilerinin hâlâ geçerli olduğunu sonradan anlamaya çalışmaktan daha öngörülebilir bir ownership sağlar.
8. Task ve Task.detached arasındaki fark nedir?
Normal Task, actor isolation gibi önemli execution context’leri devralır. Task.detached ise bağımsız bir iş oluşturur.
SwiftUI uygulamasında ViewModel’dan başlattığım işlerin çoğu feature’ın lifecycle’ına aittir. Örneğin proje yükleme yalnızca o proje aktifken anlamlıdır; bu nedenle normal Task doğal seçimdir.
Bir işi “arka plana atmak” için doğrudan Task.detached kullanmam. Bu, ownership ve isolation’ı zorlaştırır. Detached task’ı yalnızca bağımsız yaşam süresine gerçekten ihtiyaç varsa ve cancellation ile concurrency safety’yi açıkça yönettiysem kullanırım.
9. Actor’lar hangi problemi çözer?
Actor’lar concurrent erişilebilen mutable state’i korur.
Pratik bir örnek, birkaç API request’i tarafından kullanılan authentication service’tir. Birden fazla request aynı anda 401 alırsa hepsi access token refresh başlatabilir. Bu, birden çok refresh request’ine ve credential güncellenirken race condition’a neden olabilir.
Token state’ini actor içinde izole eder ve çağıranların aynı refresh operasyonunu beklemesini sağlarım. Süresi dolmuş token ile birkaç concurrent request göndererek test ederim. Başarılı sonuç tek bir refresh çalışması ve bekleyen tüm request’lerin yeni token ile devam etmesidir.
10. @MainActor ne yapar?
@MainActor, kodu main actor üzerinde izole eder ve özellikle UI’ın doğrudan tükettiği state için faydalıdır.
Bir SwiftUI projesinde ViewModel loading, error, project ve export state’ini birkaç view’a açıyordu. Her UI mutation’ında manuel olarak main queue’ya dispatch etmek yerine ViewModel’ı main actor üzerinde izole ettim.
Network ve media operasyonları asynchronous çalışmaya devam etti; state mutation doğru isolation context’inde devam etti. Bu yaklaşım thread ownership’i görünür kıldı ve dağınık
DispatchQueue.main.asynckodunu azalttı. UI’ı bloklamaması için pahalı synchronous işlemleri main actor dışında tuttum.
11. Sendable nedir?
Sendable, concurrency domain’leri arasında güvenle taşınabilen veriyi ifade eder.
Swift concurrency kullanırken immutable configuration model’lerinin value type oldukları için component’ler arasında kolayca taşındığını gördüm. Sorunlar mutable reference state içeren service’lerde ortaya çıktı.
Bu class’ları hemen
@unchecked Sendableyapmak yerine mutable state’in gerçekten concurrency boundary’sini geçmesi gerekip gerekmediğini araştırdım. Bazı durumlarda state’i actor arkasında tutmak veya immutable snapshot geçirmek daha güvenliydi. Strict concurrency uyarılarını, production race condition’a dönüşebilecek belirsiz ownership’i gösteren yararlı sinyaller olarak görüyorum.
12. SwiftUI’ın en büyük avantajları nelerdir?
SwiftUI declarative ve state-driven bir UI modeli sunar.
Bir editor ekranında slider’lar, preset seçimi, playback state ve processing değerleri aynı configuration’a bağlıydı. Imperative update’lerde her state değişikliğinde birkaç control’ü manuel olarak güncellemek gerekiyordu.
Bunun yerine tek bir coherent editor state açığa çıkardım ve SwiftUI hiyerarşisinin arayüzü bu state’ten türetmesini sağladım. Kullanıcı preset seçtiğinde configuration değişti ve ilgili tüm control’ler otomatik olarak güncellendi. Böylece synchronization kodu azaldı ve UI’ın gerçek processing state’iyle çelişmesi zorlaştı.
13. @State ve @Binding arasındaki fark nedir?
@State mevcut view’ın sahip olduğu state’tir. @Binding ise başka bir yerde sahip olunan state’e yazılabilir erişim sağlar.
Tekrar kullanılabilir bir audio-control component’inde slider bulunuyordu. İlk başta değer component’in içindeydi. Parent ekran preset seçtiğinde aynı değeri değiştirmek isteyince iki source of truth oluştu.
Gerçek processing değerinin ownership’ini parent state’e taşıdım ve control’e binding geçtim. Bundan sonra preset seçimi veya doğrudan kullanıcı etkileşimi aynı temel değeri tutarlı biçimde güncelledi.
14. State hoisting nedir?
State hoisting, state’i gerçekten sahiplenmesi gereken component’e taşımak ve value ile action’ları child component’lere geçirmektir.
Bir settings ekranında child component processing seçeneğini kendi içinde tutuyordu; ancak kullanıcı profile değiştirdiğinde aynı değer parent tarafından da değiştirilmeliydi. Parent ve child’da iki kopya tutmak synchronization kodu gerektiriyordu.
State’i ortak owner’a taşıdım ve child’ın değeri render edip kullanıcı aksiyonlarını bildirmesini sağladım. Böylece single source of truth korundu. Ancak geçici bir tooltip’in açık olup olmadığı gibi yalnızca görsel state’leri gereksiz yere hoist etmem.
15. SwiftUI view’ının güncellenmesine ne sebep olur?
SwiftUI, bağlı olduğu state değiştiğinde view’ı yeniden değerlendirir. Performans açısından önemli soru, bu değerlendirme sırasında hangi işlerin yapıldığıdır.
Bir list ekranında filtering ve sorting doğrudan view body içinde yapılıyordu. Çalışıyor olsa da ilgisiz bir UI state değiştiğinde dönüşüm tekrar çalışıyordu.
Dönüşümü ViewModel’a taşıdım ve view’a hazırlanmış display state verdim. Aynı etkileşimi tekrar profilleyince UI daha öngörülebilir oldu ve pahalı işler rendering’e bağlı olmaktan çıktı.
16. SwiftUI performans problemlerini nasıl araştırırsınız?
Önce Instruments ve SwiftUI profiling araçlarıyla ölçüm yaparım; framework’ün yavaş olduğunu varsayarak başlamam.
Yüzlerce item içeren bir proje listesinde frame drop olduğunu düşünelim. Gerçekçi veriyle problemi tekrar üretir, CPU ve allocation’ları profiller, bir item değiştiğinde gereğinden büyük bir view hiyerarşisinin invalidate olup olmadığını incelerim.
Stable identifier, model stability, row içindeki pahalı hesaplamalar, image loading ve observed state granularity’yi kontrol ederim. Her anlamlı değişiklikten sonra aynı scrolling senaryosunu tekrar çalıştırıp ölçümleri karşılaştırırım. Optimizasyon ancak ölçülen davranışı gerçekten iyileştiriyorsa değerlidir.
17. Hangi durumlarda UIKit kullanmaya devam edersiniz?
Olgun codebase’lerde, mevcut mimaride, özel component’lerde ve kademeli migration sürecinde UIKit hâlâ doğru seçim olabilir.
Established bir uygulamaya katıldığımda navigation ve kritik ekranlar stabil UIKit koduysa sırf SwiftUI daha yeni diye rewrite önermem. SwiftUI’ın net değer sağlayacağı feature sınırlarını belirler ve gerekirse
UIHostingControllerile kademeli olarak eklerim.Business ve data logic her iki UI framework’ünden bağımsız kalmalıdır. Bu yaklaşım migration riskini azaltırken uygulamanın modernleşmesini sağlar. Senior mühendislik, çalışan yazılımı ne zaman yeniden yazmamak gerektiğini de bilmektir.
18. MVVM nedir?
MVVM, presentation state’i UI rendering’den ayırır.
Bir feature’da ekran zaman içinde networking, formatting, loading, persistence ve navigation davranışlarını toplamıştı. Bu durum hem test etmeyi hem de değişiklik yapmayı zorlaştırıyordu.
Data access’i repository’lere taşıdım, presentation state ve kullanıcı aksiyonlarını ViewModel’a aldım. SwiftUI view’ı mevcut state’i render edip etkileşimleri iletti. Loading, success, error ve state transition’larını UI çalıştırmadan unit test edebildim. Sonuç yalnızca daha küçük dosyalar değil, daha net sorumluluklardı.
19. Clean Architecture nedir?
Clean Architecture’ın temel amacı business rule’ları framework ve infrastructure detaylarından bağımsız tutmaktır.
Bir uygulamada API response model’leri presentation katmanına doğrudan sızmıştı. Backend schema değişikliği birden çok UI component’ini etkiliyordu.
Business rule’ların önemli olduğu feature’da domain representation ekledim ve mapping’i data boundary’sine aldım. Networking değişiklikleri daha küçük bir alanda kaldı ve domain testleri transport model’lerine ihtiyaç duymadı. Her basit ekran için aynı abstraction sayısını eklemedim; gereksiz katmanların da bakım maliyeti vardır.
20. 1.500 satırlık bir ViewModel ile ne yaparsınız?
Önce dosyayı satır sayısına göre değil, sahip olduğu sorumluluklara göre incelerim.
Feature class’larının networking, validation, navigation, analytics, formatting, persistence ve UI state biriktirdiğini gördüm. Önce mevcut davranışı testlerle korurum. Sonra data access için repository, tekrar kullanılabilir business rule’lar için domain logic, navigation için uygun bir coordinator ve analytics gibi infrastructure işleri için ayrı interface’ler çıkarırım.
Tam rewrite’tan kaçınırım; olgun bir feature’da kaybedilmesi kolay davranışlar bulunur. Hedefim belirli bir satır sayısına ulaşmak değil, bağımsız gelişebilen component’ler oluşturmaktır.
21. Networking katmanını nasıl tasarlarsınız?
HTTP transport detaylarını domain’e dönük application API’lerinden ayırırım.
Production uygulamasında her ViewModel’ın
URLRequestoluşturmasını, JSON decode etmesini, HTTP status code yorumlamasını ve token refresh yapmasını istemem. Request execution ve decoding’i API client arkasına koyar, authentication davranışını merkezileştirir ve feature operasyonlarını repository üzerinden açarım.ViewModel böylece endpoint path’ini bilmeden
loadProjects()gibi anlamlı bir operasyon çağırabilir. Bu sınır dependency injection için de doğal bir test noktasıdır; gerçek network yerine fake repository ile ekran davranışını doğrulayabilirim.
22. API hatalarını nasıl yönetirsiniz?
Hataları uygulamanın onlar hakkında ne yapabileceğine göre sınıflandırırım.
Bir production akışında timeout, validation failure, authentication failure ve server error aynı generic handler ile ele alınıyordu. Bu hem kullanıcı mesajlarını anlamsızlaştırıyor hem de riskli retry davranışı oluşturuyordu.
Transport error’ları domain error’lardan ayırdım. Timeout için retry sunulabilir, expired token authentication recovery başlatabilir, validation error kullanıcıya gösterilebilir. Write operasyonlarında retry’nin güvenli olup olmadığını ve server’ın idempotency destekleyip desteklemediğini ayrıca değerlendirdim. Sonuç daha anlaşılır UI feedback ve daha güvenli failure handling oldu.
23. Offline-first bir özelliği nasıl tasarlarsınız?
Offline-first tasarımda local data UI’ın gözlemlediği kaynak, network ise synchronization mekanizması olur.
Bağlantının kesilebildiği bir inspection uygulamasında kullanıcı değişikliklerini hemen local olarak kaydeder ve senkronize edilmemiş kayıtları pending olarak işaretlerim. Bağlantı geldiğinde synchronization layer pending değişiklikleri gönderir ve remote güncellemeleri işler.
Last-write-wins yaklaşımını her alanda kullanmak yerine conflict davranışını önceden tanımlarım. Offline editing, app termination, reconnection, duplicate request ve çakışan değişiklikleri test ederim. Hedef kullanıcı network’ü düşünmeden çalışırken sistemin veri bütünlüğünü korumasıdır.
24. SwiftData mı, Core Data mı?
Uygun deployment target’a sahip yeni ve basit persistence gereksinimli projelerde SwiftData’yı değerlendiririm. Olgun bir uygulamada ise migration riski kararın parçasıdır.
Yıllarca Core Data migration’ı ve stabil production verisi olan bir uygulamada sırf SwiftData daha yeni API’ye sahip diye rewrite önermem. Önce migration’ın hangi problemi çözdüğünü, hangi capability’lere bağlı olduğumuzu ve mevcut kullanıcı verisinin güvenle nasıl taşınacağını araştırırım.
Business benefit küçük, migration riski yüksekse Core Data’yı korumak daha iyi mühendislik kararı olabilir. Persistence değişikliğini framework modası değil ürün riski olarak değerlendiririm.
25. Keychain’de neler saklanmalıdır?
Keychain; authentication credential’ları, token’lar ve cryptographic material gibi hassas ve kalıcı veriler için kullanılmalıdır.
Authenticated API erişimi olan bir uygulamada refresh credential’larını Keychain’de, seçili tema veya UI configuration gibi normal tercihleri ise normal preference store’da tutarım.
Credential lifecycle’ını da açıkça tanımlarım. Logout yalnızca görünen UI state’ini değiştirmemeli, ilgili secure credential’ları da temizlemelidir. Aksi durumda uygulama logged out görünürken hassas authentication material hâlâ erişilebilir kalabilir.
26. iOS test stratejiniz nedir?
Farklı riskleri farklı test seviyeleriyle doğrularım.
Subscription veya purchase feature’ında fiyat ve state transition logic’ini hızlı unit test’lerle korurum. Repository ve API davranışını integration boundary’lerinde test ederim. UI testlerini authentication veya purchase tamamlama gibi daha az sayıdaki kritik kullanıcı yolculuğuna ayırırım.
Production bug’ı oluştuğunda gerçek failure mode’u çevreleyen focused regression coverage eklerim. Böylece her business rule’ü yavaş UI automation ile doğrulamadan hızlı CI feedback ve anlamlı engineering confidence elde ederim.
27. Asynchronous kodu nasıl test edersiniz?
Zamana güvenmek yerine dependency’leri kontrol etmeye çalışırım.
Bir filtre değiştiğinde network request başladığını düşünelim. Kullanıcı A seçeneğini, sonra B’yi seçerse A request’i B’den sonra tamamlanıp daha yeni state’i overwrite edebilir.
Testte response’ların ne zaman tamamlanacağını kontrol ettiğim fake repository kullanırım. B’yi önce, A’yı sonra tamamlatır ve A’nın visible state’i güncelleyemediğini doğrularım. Bu, ilgilendiğim concurrency kuralını doğrudan kanıtlar; testin içine sleep eklemekten çok daha güvenilirdir.
28. Regression’ları nasıl önlersiniz?
Önemli bir production bug’ı mümkünse arkasında bir test bırakmalıdır.
Uygulama asynchronous bir operasyon sırasında background’a alınıp geri döndüğünde kullanıcıların zaman zaman crash yaşadığını varsayalım. Lifecycle sequence’ini yeniden üretir, hangi state veya nesnenin geçersiz hâle geldiğini bulur ve yalnızca crashing line’ı korumak yerine ownership problemini düzeltirim.
Ardından hatayı yakalayan en dar otomatik testi eklerim. Deployment’tan sonra aynı crash signature’ını production’da izlemeye devam ederim. Regression testi bilinen hatanın geri gelmesini, monitoring ise gerçek kullanıcı probleminin ortadan kalktığını doğrular.
29. Production crash’ini nasıl araştırırsınız?
Stack trace, app version, iOS version, device, breadcrumb, log, kullanıcı akışı ve son release’lerden oluşan production kanıtıyla başlarım.
Önce crash’in belirli bir feature veya lifecycle event etrafında kümelenip kümelenmediğini bulurum. Raporların çoğu background’dan dönüşte oluşuyorsa bu geçişi network state ve asynchronous work timing’ini değiştirerek reproduce ederim.
Kök nedeni bulduktan sonra yalnızca crash eden satırı korumak yerine ownership veya state problemini düzeltmeyi tercih ederim. Regression coverage ekler, değişikliği kontrollü yayınlar ve rollout sonrasında aynı crash grubunu izlerim.
Daha önce production’da bu kanıta dayalı araştırma ve düzeltme yaklaşımıyla crash oranının yaklaşık yüzde 4’ten yüzde 1’e düşürülmesine katkı sağladım. Ölçülebilir sonuç, cevabın production etkisini görünür kılar.
30. iOS ekibine hangi soruları sorarsınız?
Ekibin gerçek mühendislik ortamını anlamak için şu soruları sorarım: “iOS codebase’inin bugün karşılaştığı en büyük teknik problemler neler?” “Uygulamanın ne kadarı SwiftUI, ne kadarı UIKit?” “Swift’in strict concurrency model’ini aktif olarak benimsiyor musunuz?” “Crash-free session, startup performance, memory kullanımı ve responsiveness’ı nasıl ölçüyorsunuz?” “Mimari kararlar nasıl öneriliyor ve gözden geçiriliyor?” “Teknik borcun ele alınacağına nasıl karar veriyorsunuz?” “Bir mühendis feature yayınladıktan sonra production metric’leri ve incident’ları da sahipleniyor mu?” “iOS, backend, QA, design ve product ekipleri nasıl çalışıyor?” “Senior iOS mühendisin ilk üç ila altı ay içinde neyi iyileştirmesini bekliyorsunuz?”
Takip Sorularına Nasıl Cevap Verilir?
En büyük hatalardan biri yalnızca ilk cevabı hazırlamaktır. “Performansı iyileştirdim” derseniz “Nasıl ölçtün?”; “StateFlow kullandım” derseniz iOS bağlamında “Neden bu state modelini seçtin?”; “Clean Architecture kullandım” derseniz “Bu mimarinin maliyeti neydi?”; “Crash’i düzelttim” derseniz “Nasıl reproduce ettin?” sorularını bekleyin.
Kullanışlı bir kural şudur: Mülakatta bir teknoloji adını, onun hakkında iki veya üç seviye takip sorusuna hazır değilseniz kullanmayın.
Hatırlanacak Basit Formüller
Production deneyimi için:
Durum → Problem → Araştırma → Karar → Uygulama → Doğrulama → Sonuç
Teknik kavramlar için:
Tanım → Neden var → Ne zaman kullanırım → Ödünleşim → Gerçek örnek
Mimari için:
Gereksinimler → Kısıtlar → Seçenekler → Karar → Ödünleşimler → Doğrulama
Debugging için:
Gözle → Ölç → Yeniden üret → İzole et → Düzelt → Test et → İzle
iOS teknik mülakatına hazırlanırken hedef yalnızca Swift API’lerini ezberlemek olmamalıdır. State, lifecycle, network, persistence, performance, test ve release problemlerini gerçek bir uygulamada nasıl ele aldığınızı anlatabilmelisiniz.
Güçlü cevap; problemi netleştirir, kararın nedenini açıklar, ödünleşimi kabul eder, sonucu ölçer ve production sorumluluğunu gösterir. Böyle cevap verdiğinizde API ezberlemiş biri gibi değil, iOS yazılımını gerçek hayatta işletmiş bir mühendis gibi görünürsünüz.