# 2026'da MapKit SwiftUI Mülakatı: Açıklamalar, Kaplamalar ve Konum Belirleme > iOS mülakatları için SwiftUI ile MapKit'te uzmanlaşın: özel açıklamalar, kaplamalar, konum belirleme, yer arama ve Maps entegrasyon kalıpları. - Published: 2026-03-10 - Updated: 2026-04-29 - Author: SharpSkill - Tags: mapkit, swiftui, ios, geolocation, interview - Reading time: 14 min --- Haritalar birçok iOS uygulamasında temel bir özellik olarak yer alır: teslimat, fitness, emlak ve konum tabanlı sosyal ağlar. iOS 17'den itibaren MapKit, harita entegrasyonunu önemli ölçüde basitleştiren native bir SwiftUI API'si sunmaktadır. İşe alım uzmanları teknik mülakatlarda bu yetkinlikleri düzenli olarak değerlendirmektedir. > **Rehber Yapısı** > > Her soru, gerçek bir teknik mülakatın formatını yansıtır; ayrıntılı yanıtlar ve çalışan kod içerir. Kavramlar temel düzeyden ileri düzeye doğru ilerler. ## SwiftUI'de Harita Temelleri ### Soru 1: SwiftUI ile temel bir harita nasıl gösterilir? iOS 17'den itibaren SwiftUI, önceki `UIViewRepresentable` yaklaşımının yerini alan native `Map` bileşenini sunar. `Map` görünümü bir kamera konumu ve gösterilecek içerik kabul eder. ```swift // BasicMapView.swift import SwiftUI import MapKit struct BasicMapView: View { // Camera position controlling center and zoom @State private var cameraPosition: MapCameraPosition = .automatic var body: some View { // Basic map without additional content Map(position: $cameraPosition) } } // Map centered on a specific region struct CenteredMapView: View { // Defines a region centered on Paris @State private var cameraPosition: MapCameraPosition = .region( MKCoordinateRegion( center: CLLocationCoordinate2D(latitude: 48.8566, longitude: 2.3522), // Span defines the zoom level (in degrees) span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05) ) ) var body: some View { Map(position: $cameraPosition) { // Map content (markers, annotations, etc.) } .mapStyle(.standard) // Map style: standard, imagery, hybrid } } ``` `position` özelliği farklı modlara izin veren bir enum olan `MapCameraPosition` kullanır: `.automatic` (otomatik ayarlama), `.region` (sabit bölge), `.camera` (tam kontrol) veya `.userLocation` (kullanıcıya ortalanmış). ### Soru 2: Mevcut farklı harita stilleri nelerdir? MapKit, farklı kullanım durumlarına uygun çeşitli harita stilleri sunar. `.mapStyle()` modifier'ı haritanın görsel görünümünü yapılandırır. ```swift // MapStyles.swift import SwiftUI import MapKit struct MapStylesDemo: View { @State private var position: MapCameraPosition = .automatic @State private var selectedStyle: MapStyleOption = .standard var body: some View { VStack { Map(position: $position) .mapStyle(selectedStyle.style) .frame(height: 400) // Style selector Picker("Style", selection: $selectedStyle) { ForEach(MapStyleOption.allCases) { option in Text(option.name).tag(option) } } .pickerStyle(.segmented) .padding() } } } enum MapStyleOption: String, CaseIterable, Identifiable { case standard case imagery case hybrid case standardElevated case imageryElevated var id: String { rawValue } var name: String { switch self { case .standard: return "Standard" case .imagery: return "Satellite" case .hybrid: return "Hybrid" case .standardElevated: return "Terrain" case .imageryElevated: return "Satellite 3D" } } var style: MapStyle { switch self { case .standard: // Classic road map return .standard case .imagery: // Satellite view without labels return .imagery case .hybrid: // Satellite with roads and names return .hybrid case .standardElevated: // Standard with 3D terrain return .standard(elevation: .realistic) case .imageryElevated: // Satellite with 3D terrain return .imagery(elevation: .realistic) } } } ``` > **İlgi Noktaları** > > `.standard` stili, gösterilen kategorileri filtrelemek için bir `pointsOfInterest` parametresi kabul eder: `.including([.restaurant, .cafe])` veya `.excluding([.nightlife])`. ### Soru 3: Haritaya işaretçiler ve açıklamalar nasıl eklenir? İşaretçiler haritada ilgi noktalarını temsil eder. SwiftUI MapKit çeşitli türler sunar: `Marker` (standart pin), `Annotation` (özel görünüm) ve `MapCircle`/`MapPolygon` (geometrik şekiller). ```swift // MarkersAndAnnotations.swift import SwiftUI import MapKit // Place model conforming to Identifiable struct Place: Identifiable { let id = UUID() let name: String let coordinate: CLLocationCoordinate2D let category: PlaceCategory } enum PlaceCategory { case restaurant, hotel, attraction var icon: String { switch self { case .restaurant: return "fork.knife" case .hotel: return "bed.double" case .attraction: return "star" } } var tint: Color { switch self { case .restaurant: return .orange case .hotel: return .blue case .attraction: return .purple } } } struct MarkersMapView: View { @State private var position: MapCameraPosition = .region( MKCoordinateRegion( center: CLLocationCoordinate2D(latitude: 48.8566, longitude: 2.3522), span: MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1) ) ) let places: [Place] = [ Place(name: "Eiffel Tower", coordinate: CLLocationCoordinate2D(latitude: 48.8584, longitude: 2.2945), category: .attraction), Place(name: "Le Meurice", coordinate: CLLocationCoordinate2D(latitude: 48.8651, longitude: 2.3281), category: .hotel), Place(name: "Le Jules Verne", coordinate: CLLocationCoordinate2D(latitude: 48.8583, longitude: 2.2944), category: .restaurant) ] var body: some View { Map(position: $position) { // Markers with system icon ForEach(places) { place in Marker(place.name, systemImage: place.category.icon, coordinate: place.coordinate) .tint(place.category.tint) } } } } // Custom annotations with SwiftUI view struct CustomAnnotationsView: View { @State private var position: MapCameraPosition = .automatic @State private var selectedPlace: Place? let places: [Place] = [] // Data var body: some View { Map(position: $position, selection: $selectedPlace) { ForEach(places) { place in // Annotation with custom view Annotation(place.name, coordinate: place.coordinate) { PlaceAnnotationView(place: place, isSelected: selectedPlace?.id == place.id) } } } } } // Custom view for annotation struct PlaceAnnotationView: View { let place: Place let isSelected: Bool var body: some View { VStack(spacing: 4) { // Icon with colored background Image(systemName: place.category.icon) .font(.system(size: isSelected ? 20 : 16)) .foregroundStyle(.white) .padding(8) .background(place.category.tint) .clipShape(Circle()) .shadow(radius: 4) // Name displayed when selected if isSelected { Text(place.name) .font(.caption) .fontWeight(.medium) .padding(.horizontal, 8) .padding(.vertical, 4) .background(.ultraThinMaterial) .clipShape(RoundedRectangle(cornerRadius: 8)) } } .animation(.spring(duration: 0.3), value: isSelected) } } ``` Temel fark: `Marker` native Apple Maps render'ını (standart pin) kullanırken, `Annotation` herhangi bir SwiftUI görünümüyle tam özelleştirmeye olanak tanır. ## Konum Belirleme ve İzinler ### Soru 4: Konum izinleri nasıl yönetilir ve kullanıcı konumu nasıl gösterilir? Konum belirleme açık izinler ve farklı yetkilendirme durumlarının doğru şekilde ele alınmasını gerektirir. `CLLocationManager` izin isteklerini yönetir. ```swift // LocationManager.swift import SwiftUI import MapKit import CoreLocation @Observable class LocationManager: NSObject, CLLocationManagerDelegate { private let manager = CLLocationManager() // Location state var location: CLLocation? var authorizationStatus: CLAuthorizationStatus = .notDetermined var isAuthorized: Bool { authorizationStatus == .authorizedWhenInUse || authorizationStatus == .authorizedAlways } override init() { super.init() manager.delegate = self manager.desiredAccuracy = kCLLocationAccuracyBest // Get current status authorizationStatus = manager.authorizationStatus } // Request location permission func requestAuthorization() { manager.requestWhenInUseAuthorization() } // Start location tracking func startUpdatingLocation() { guard isAuthorized else { return } manager.startUpdatingLocation() } // Stop tracking to save battery func stopUpdatingLocation() { manager.stopUpdatingLocation() } // MARK: - CLLocationManagerDelegate func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { authorizationStatus = manager.authorizationStatus if isAuthorized { startUpdatingLocation() } } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { // Take the most recent position location = locations.last } func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { print("Location error: \(error.localizedDescription)") } } // View with map and user location struct UserLocationMapView: View { @State private var locationManager = LocationManager() @State private var cameraPosition: MapCameraPosition = .userLocation(fallback: .automatic) var body: some View { Map(position: $cameraPosition) { // Display the blue user location dot UserAnnotation() } .mapControls { // Button to recenter on position MapUserLocationButton() // Compass MapCompass() // Scale MapScaleView() } .onAppear { locationManager.requestAuthorization() } .overlay(alignment: .top) { if !locationManager.isAuthorized { PermissionBanner() } } } } // Banner requesting authorization struct PermissionBanner: View { var body: some View { HStack { Image(systemName: "location.slash") Text("Enable location in Settings") Spacer() Button("Open") { if let url = URL(string: UIApplication.openSettingsURLString) { UIApplication.shared.open(url) } } .buttonStyle(.bordered) } .padding() .background(.ultraThinMaterial) } } ``` > **Zorunlu Info.plist** > > `NSLocationWhenInUseUsageDescription` ve/veya `NSLocationAlwaysUsageDescription` anahtarları, konum kullanımının net bir açıklamasıyla Info.plist'te tanımlanmalıdır. ### Soru 5: Gerçek zamanlı konum nasıl izlenir ve bir rota nasıl çizilir? Gerçek zamanlı izleme, fitness veya navigasyon uygulamaları için kritik önemdedir. Bu soru, sürekli konum verisi akışını yönetme becerisini sınar. ```swift // RouteTrackingView.swift import SwiftUI import MapKit import CoreLocation @Observable class RouteTracker: NSObject, CLLocationManagerDelegate { private let manager = CLLocationManager() // Position history for the trace var routeCoordinates: [CLLocationCoordinate2D] = [] var currentLocation: CLLocation? var isTracking = false // Route statistics var totalDistance: CLLocationDistance = 0 private var lastLocation: CLLocation? override init() { super.init() manager.delegate = self manager.desiredAccuracy = kCLLocationAccuracyBest // Update even in background manager.allowsBackgroundLocationUpdates = true manager.pausesLocationUpdatesAutomatically = false } func startTracking() { manager.requestWhenInUseAuthorization() manager.startUpdatingLocation() isTracking = true routeCoordinates = [] totalDistance = 0 lastLocation = nil } func stopTracking() { manager.stopUpdatingLocation() isTracking = false } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { guard let newLocation = locations.last else { return } // Filter inaccurate positions guard newLocation.horizontalAccuracy < 20 else { return } currentLocation = newLocation routeCoordinates.append(newLocation.coordinate) // Calculate distance traveled if let last = lastLocation { totalDistance += newLocation.distance(from: last) } lastLocation = newLocation } } struct RouteTrackingView: View { @State private var tracker = RouteTracker() @State private var cameraPosition: MapCameraPosition = .userLocation(fallback: .automatic) var body: some View { ZStack { Map(position: $cameraPosition) { // Current position UserAnnotation() // Route trace as polyline if tracker.routeCoordinates.count > 1 { MapPolyline(coordinates: tracker.routeCoordinates) .stroke(.blue, lineWidth: 4) } } .mapStyle(.standard) // Control interface VStack { Spacer() // Statistics HStack { VStack(alignment: .leading) { Text("Distance") .font(.caption) .foregroundStyle(.secondary) Text(formatDistance(tracker.totalDistance)) .font(.title2) .fontWeight(.bold) } Spacer() } .padding() .background(.ultraThinMaterial) .clipShape(RoundedRectangle(cornerRadius: 12)) .padding() // Start/stop button Button { if tracker.isTracking { tracker.stopTracking() } else { tracker.startTracking() } } label: { Label( tracker.isTracking ? "Stop" : "Start", systemImage: tracker.isTracking ? "stop.fill" : "play.fill" ) .frame(maxWidth: .infinity) } .buttonStyle(.borderedProminent) .tint(tracker.isTracking ? .red : .green) .padding(.horizontal) .padding(.bottom) } } } private func formatDistance(_ meters: CLLocationDistance) -> String { if meters < 1000 { return String(format: "%.0f m", meters) } else { return String(format: "%.2f km", meters / 1000) } } } ``` ## Kaplamalar ve Geometrik Şekiller ### Soru 6: Haritaya özel kaplamalar nasıl çizilir? Kaplamalar, harita üzerinde bölgeler, rotalar veya alanlar göstermeye olanak tanır. SwiftUI MapKit `MapCircle`, `MapPolygon` ve `MapPolyline` sunar. ```swift // MapOverlays.swift import SwiftUI import MapKit struct DeliveryZoneMapView: View { @State private var position: MapCameraPosition = .region( MKCoordinateRegion( center: CLLocationCoordinate2D(latitude: 48.8566, longitude: 2.3522), span: MKCoordinateSpan(latitudeDelta: 0.15, longitudeDelta: 0.15) ) ) // Delivery zones with different times let deliveryZones: [DeliveryZone] = [ DeliveryZone( name: "Express Zone", center: CLLocationCoordinate2D(latitude: 48.8566, longitude: 2.3522), radius: 2000, deliveryTime: "15 min", color: .green ), DeliveryZone( name: "Standard Zone", center: CLLocationCoordinate2D(latitude: 48.8566, longitude: 2.3522), radius: 5000, deliveryTime: "30 min", color: .orange ) ] var body: some View { Map(position: $position) { // Circles for delivery zones ForEach(deliveryZones) { zone in MapCircle(center: zone.center, radius: zone.radius) .foregroundStyle(zone.color.opacity(0.2)) .stroke(zone.color, lineWidth: 2) } // Restaurant marker Marker("Restaurant", systemImage: "storefront", coordinate: CLLocationCoordinate2D(latitude: 48.8566, longitude: 2.3522)) .tint(.red) } .overlay(alignment: .bottomLeading) { // Legend VStack(alignment: .leading, spacing: 8) { ForEach(deliveryZones) { zone in HStack { Circle() .fill(zone.color) .frame(width: 12, height: 12) Text("\(zone.name) - \(zone.deliveryTime)") .font(.caption) } } } .padding() .background(.ultraThinMaterial) .clipShape(RoundedRectangle(cornerRadius: 8)) .padding() } } } struct DeliveryZone: Identifiable { let id = UUID() let name: String let center: CLLocationCoordinate2D let radius: CLLocationDistance let deliveryTime: String let color: Color } // Custom polygon (complex geographic zone) struct PolygonOverlayView: View { @State private var position: MapCameraPosition = .automatic // Neighborhood coordinates let neighborhoodCoordinates: [CLLocationCoordinate2D] = [ CLLocationCoordinate2D(latitude: 48.853, longitude: 2.347), CLLocationCoordinate2D(latitude: 48.858, longitude: 2.352), CLLocationCoordinate2D(latitude: 48.862, longitude: 2.348), CLLocationCoordinate2D(latitude: 48.860, longitude: 2.340), CLLocationCoordinate2D(latitude: 48.855, longitude: 2.342) ] var body: some View { Map(position: $position) { // Polygon automatically closed MapPolygon(coordinates: neighborhoodCoordinates) .foregroundStyle(.blue.opacity(0.3)) .stroke(.blue, lineWidth: 3) } } } ``` ### Soru 7: İki nokta arasında bir rota nasıl gösterilir? Rota hesaplama, Apple sunucularından yol almak için `MKDirections` kullanır. Görüntüleme daha sonra `MapPolyline` ile yapılır. ```swift // RouteDirections.swift import SwiftUI import MapKit @Observable class RouteCalculator { var route: MKRoute? var isCalculating = false var error: String? // Calculate route between two points func calculateRoute(from source: CLLocationCoordinate2D, to destination: CLLocationCoordinate2D) async { isCalculating = true error = nil // Create source and destination placemarks let sourcePlacemark = MKPlacemark(coordinate: source) let destinationPlacemark = MKPlacemark(coordinate: destination) // Configure request let request = MKDirections.Request() request.source = MKMapItem(placemark: sourcePlacemark) request.destination = MKMapItem(placemark: destinationPlacemark) request.transportType = .automobile // .walking, .transit available request.requestsAlternateRoutes = false let directions = MKDirections(request: request) do { let response = try await directions.calculate() // Take the first route route = response.routes.first } catch { self.error = error.localizedDescription } isCalculating = false } } struct DirectionsMapView: View { @State private var calculator = RouteCalculator() @State private var position: MapCameraPosition = .automatic let startPoint = CLLocationCoordinate2D(latitude: 48.8738, longitude: 2.2950) // Arc de Triomphe let endPoint = CLLocationCoordinate2D(latitude: 48.8530, longitude: 2.3499) // Notre-Dame var body: some View { ZStack { Map(position: $position) { // Start and end markers Marker("Start", systemImage: "car.fill", coordinate: startPoint) .tint(.green) Marker("End", systemImage: "flag.fill", coordinate: endPoint) .tint(.red) // Route trace if let route = calculator.route { MapPolyline(route.polyline) .stroke(.blue, lineWidth: 5) } } // Route information if let route = calculator.route { VStack { Spacer() RouteInfoCard(route: route) } } if calculator.isCalculating { ProgressView("Calculating route...") .padding() .background(.ultraThinMaterial) .clipShape(RoundedRectangle(cornerRadius: 8)) } } .task { await calculator.calculateRoute(from: startPoint, to: endPoint) } } } struct RouteInfoCard: View { let route: MKRoute var body: some View { HStack(spacing: 20) { VStack(alignment: .leading) { Text("Distance") .font(.caption) .foregroundStyle(.secondary) Text(formatDistance(route.distance)) .font(.headline) } Divider() .frame(height: 30) VStack(alignment: .leading) { Text("Estimated Time") .font(.caption) .foregroundStyle(.secondary) Text(formatDuration(route.expectedTravelTime)) .font(.headline) } Spacer() } .padding() .background(.ultraThinMaterial) .clipShape(RoundedRectangle(cornerRadius: 12)) .padding() } private func formatDistance(_ meters: CLLocationDistance) -> String { let km = meters / 1000 return String(format: "%.1f km", km) } private func formatDuration(_ seconds: TimeInterval) -> String { let minutes = Int(seconds) / 60 if minutes < 60 { return "\(minutes) min" } else { let hours = minutes / 60 let remainingMinutes = minutes % 60 return "\(hours)h \(remainingMinutes)min" } } } ``` ## Yer Arama ve Coğrafi Kodlama ### Soru 8: MKLocalSearch ile yer arama nasıl uygulanır? `MKLocalSearch`, ilgi noktaları, adresler veya işletmeler için arama yapmaya olanak tanır. Bu özellik, konum bazlı arama çubuğu olan uygulamalar için temel önemdedir. ```swift // PlaceSearch.swift import SwiftUI import MapKit @Observable class PlaceSearchManager { var searchResults: [MKMapItem] = [] var isSearching = false var searchText = "" private var searchTask: Task? // Search with debounce func search(query: String, in region: MKCoordinateRegion) { searchTask?.cancel() guard !query.isEmpty else { searchResults = [] return } searchTask = Task { // 300ms debounce try? await Task.sleep(for: .milliseconds(300)) guard !Task.isCancelled else { return } isSearching = true let request = MKLocalSearch.Request() request.naturalLanguageQuery = query request.region = region request.resultTypes = [.pointOfInterest, .address] let search = MKLocalSearch(request: request) do { let response = try await search.start() if !Task.isCancelled { searchResults = response.mapItems } } catch { print("Search error: \(error.localizedDescription)") searchResults = [] } isSearching = false } } func clearResults() { searchResults = [] searchText = "" } } struct SearchableMapView: View { @State private var searchManager = PlaceSearchManager() @State private var position: MapCameraPosition = .region( MKCoordinateRegion( center: CLLocationCoordinate2D(latitude: 48.8566, longitude: 2.3522), span: MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1) ) ) @State private var selectedItem: MKMapItem? @State private var visibleRegion: MKCoordinateRegion? var body: some View { NavigationStack { Map(position: $position, selection: $selectedItem) { // Display search results ForEach(searchManager.searchResults, id: \.self) { item in Marker(item: item) } } .onMapCameraChange { context in // Capture visible region for search visibleRegion = context.region } .searchable(text: $searchManager.searchText, prompt: "Search for a place") .onChange(of: searchManager.searchText) { _, newValue in if let region = visibleRegion { searchManager.search(query: newValue, in: region) } } .overlay(alignment: .bottom) { if let item = selectedItem { PlaceDetailCard(item: item) } } .navigationTitle("Map") .navigationBarTitleDisplayMode(.inline) } } } struct PlaceDetailCard: View { let item: MKMapItem var body: some View { VStack(alignment: .leading, spacing: 8) { Text(item.name ?? "Unknown Place") .font(.headline) if let address = item.placemark.title { Text(address) .font(.subheadline) .foregroundStyle(.secondary) } HStack { if let phone = item.phoneNumber { Button { if let url = URL(string: "tel:\(phone)") { UIApplication.shared.open(url) } } label: { Label("Call", systemImage: "phone") } .buttonStyle(.bordered) } Button { item.openInMaps() } label: { Label("Directions", systemImage: "arrow.triangle.turn.up.right.diamond") } .buttonStyle(.borderedProminent) } } .padding() .frame(maxWidth: .infinity, alignment: .leading) .background(.ultraThickMaterial) .clipShape(RoundedRectangle(cornerRadius: 16)) .padding() } } ``` ### Soru 9: Bir adres koordinatlara nasıl dönüştürülür (coğrafi kodlama)? Coğrafi kodlama, bir metin adresini GPS koordinatlarına dönüştürür. Ters coğrafi kodlama ise bunun tersini gerçekleştirir. ```swift // Geocoding.swift import SwiftUI import MapKit import CoreLocation @Observable class GeocodingManager { private let geocoder = CLGeocoder() var coordinate: CLLocationCoordinate2D? var address: String? var isLoading = false var error: String? // Geocoding: address → coordinates func geocode(address: String) async { isLoading = true error = nil do { let placemarks = try await geocoder.geocodeAddressString(address) if let placemark = placemarks.first, let location = placemark.location { coordinate = location.coordinate } else { error = "Address not found" } } catch { self.error = error.localizedDescription } isLoading = false } // Reverse geocoding: coordinates → address func reverseGeocode(coordinate: CLLocationCoordinate2D) async { isLoading = true error = nil let location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude) do { let placemarks = try await geocoder.reverseGeocodeLocation(location) if let placemark = placemarks.first { address = formatAddress(placemark) } else { error = "Address not found" } } catch { self.error = error.localizedDescription } isLoading = false } // Format readable address private func formatAddress(_ placemark: CLPlacemark) -> String { var components: [String] = [] if let street = placemark.thoroughfare { if let number = placemark.subThoroughfare { components.append("\(number) \(street)") } else { components.append(street) } } if let city = placemark.locality { components.append(city) } if let country = placemark.country { components.append(country) } return components.joined(separator: ", ") } } struct GeocodingDemoView: View { @State private var manager = GeocodingManager() @State private var addressInput = "" @State private var position: MapCameraPosition = .automatic var body: some View { VStack { // Address input field HStack { TextField("Enter an address", text: $addressInput) .textFieldStyle(.roundedBorder) Button("Search") { Task { await manager.geocode(address: addressInput) if let coord = manager.coordinate { position = .region(MKCoordinateRegion( center: coord, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01) )) } } } .buttonStyle(.borderedProminent) .disabled(addressInput.isEmpty || manager.isLoading) } .padding() // Map with marker Map(position: $position) { if let coord = manager.coordinate { Marker("Result", coordinate: coord) .tint(.red) } } if let error = manager.error { Text(error) .foregroundStyle(.red) .padding() } } } } ``` > **Coğrafi Kodlama Limitleri** > > Apple'ın coğrafi kodlayıcısı istek limitleri uygular. Yüksek hacimler için yerel önbellek ya da Mapbox veya Google Maps gibi üçüncü taraf hizmetler önerilir. ## İleri Seviye Kalıplar ve En İyi Uygulamalar ### Soru 10: Çok sayıda işaretçi ile performans nasıl optimize edilir? Yüzlerce işaretçi göstermek performansı etkileyebilir. Kümeleme ve aşamalı yükleme etkili çözümlerdir. ```swift // ClusteringMapView.swift import SwiftUI import MapKit struct ClusteringMapView: View { @State private var position: MapCameraPosition = .automatic @State private var visiblePlaces: [Place] = [] @State private var visibleRegion: MKCoordinateRegion? // All data (potentially thousands) let allPlaces: [Place] var body: some View { Map(position: $position) { // Display only visible places ForEach(visiblePlaces) { place in Marker(place.name, coordinate: place.coordinate) } } .onMapCameraChange(frequency: .onEnd) { context in // Update when user stops moving visibleRegion = context.region updateVisiblePlaces(in: context.region) } } // Filter places in visible region private func updateVisiblePlaces(in region: MKCoordinateRegion) { let minLat = region.center.latitude - region.span.latitudeDelta / 2 let maxLat = region.center.latitude + region.span.latitudeDelta / 2 let minLon = region.center.longitude - region.span.longitudeDelta / 2 let maxLon = region.center.longitude + region.span.longitudeDelta / 2 // Spatial filtering var filtered = allPlaces.filter { place in place.coordinate.latitude >= minLat && place.coordinate.latitude <= maxLat && place.coordinate.longitude >= minLon && place.coordinate.longitude <= maxLon } // Limit number of displayed markers if filtered.count > 100 { // Sampling or clustering filtered = Array(filtered.prefix(100)) } visiblePlaces = filtered } } // Simplified manual clustering struct ClusteredPlace: Identifiable { let id = UUID() let coordinate: CLLocationCoordinate2D let count: Int let places: [Place] var isCluster: Bool { count > 1 } } @Observable class ClusterManager { var clusters: [ClusteredPlace] = [] // Group nearby places based on zoom level func cluster(places: [Place], in region: MKCoordinateRegion) { let gridSize = region.span.latitudeDelta / 10 var grid: [String: [Place]] = [:] for place in places { // Grid key based on position let gridX = Int(place.coordinate.longitude / gridSize) let gridY = Int(place.coordinate.latitude / gridSize) let key = "\(gridX),\(gridY)" grid[key, default: []].append(place) } // Convert to clusters clusters = grid.map { (_, places) in let centerLat = places.map(\.coordinate.latitude).reduce(0, +) / Double(places.count) let centerLon = places.map(\.coordinate.longitude).reduce(0, +) / Double(places.count) return ClusteredPlace( coordinate: CLLocationCoordinate2D(latitude: centerLat, longitude: centerLon), count: places.count, places: places ) } } } struct ClusterAnnotationView: View { let cluster: ClusteredPlace var body: some View { if cluster.isCluster { // Display a circle with count ZStack { Circle() .fill(.blue) .frame(width: 40, height: 40) Text("\(cluster.count)") .font(.system(size: 14, weight: .bold)) .foregroundStyle(.white) } } else { // Simple marker Image(systemName: "mappin.circle.fill") .font(.title) .foregroundStyle(.red) } } } ``` ### Soru 11: MapKit diğer Apple servisleriyle nasıl entegre edilir? MapKit, zenginleştirilmiş bir deneyim sunmak için çeşitli Apple framework'leri ile entegre olur: Look Around, CarPlay, WidgetKit. ```swift // LookAroundIntegration.swift import SwiftUI import MapKit struct LookAroundMapView: View { @State private var position: MapCameraPosition = .automatic @State private var selectedPlace: Place? @State private var lookAroundScene: MKLookAroundScene? @State private var showLookAround = false let places: [Place] var body: some View { Map(position: $position, selection: $selectedPlace) { ForEach(places) { place in Marker(place.name, coordinate: place.coordinate) } } .onChange(of: selectedPlace) { _, newPlace in if let place = newPlace { Task { await loadLookAroundScene(for: place.coordinate) } } } .sheet(isPresented: $showLookAround) { if let scene = lookAroundScene { LookAroundPreview(scene: scene) .frame(height: 300) } } .safeAreaInset(edge: .bottom) { if selectedPlace != nil && lookAroundScene != nil { Button("View in Look Around") { showLookAround = true } .buttonStyle(.borderedProminent) .padding() } } } // Load Look Around scene for a position private func loadLookAroundScene(for coordinate: CLLocationCoordinate2D) async { let request = MKLookAroundSceneRequest(coordinate: coordinate) do { lookAroundScene = try await request.scene } catch { lookAroundScene = nil print("Look Around not available: \(error.localizedDescription)") } } } // Interactive Look Around component struct LookAroundPreview: View { let scene: MKLookAroundScene @State private var isNavigating = false var body: some View { LookAroundPreviewRepresentable(scene: scene, isNavigating: $isNavigating) .overlay(alignment: .topTrailing) { Button { isNavigating.toggle() } label: { Image(systemName: isNavigating ? "stop.fill" : "play.fill") .padding() .background(.ultraThinMaterial) .clipShape(Circle()) } .padding() } } } // UIViewRepresentable for Look Around struct LookAroundPreviewRepresentable: UIViewRepresentable { let scene: MKLookAroundScene @Binding var isNavigating: Bool func makeUIView(context: Context) -> MKLookAroundViewController { let controller = MKLookAroundViewController(scene: scene) controller.isNavigationEnabled = isNavigating return controller } func updateUIView(_ uiView: MKLookAroundViewController, context: Context) { uiView.isNavigationEnabled = isNavigating } } ``` ## Sonuç SwiftUI ile MapKit, iOS uygulamalarına harita entegrasyonu için modern ve güçlü bir API sağlar. Açıklamalar, kaplamalar, konum belirleme ve yer arama konusundaki ustalık, teknik mülakatlarda deneyimli iOS geliştiricilerini öne çıkarır. ### Gözden Geçirme Listesi - ✅ `Map` ile harita göstermek ve `MapCameraPosition` yapılandırmak - ✅ Farklı harita stillerini kullanmak (`standard`, `imagery`, `hybrid`) - ✅ Özel `Marker` ve `Annotation` eklemek - ✅ `CLLocationManager` ile konum izinlerini yönetmek - ✅ Gerçek zamanlı konumu izlemek ve rota çizmek - ✅ Kaplamalar çizmek (`MapCircle`, `MapPolygon`, `MapPolyline`) - ✅ `MKDirections` ile rotaları hesaplamak - ✅ `MKLocalSearch` ile yer arama uygulamak - ✅ Coğrafi kodlama ve ters coğrafi kodlama yapmak - ✅ İşaretçi kümeleme ile performansı optimize etmek - ✅ İmmersif görünüm için Look Around entegre etmek --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/tr/blog/ios/mapkit-swiftui-interview-annotations-overlays-geolocation