Swift: не просто язык для «яблочных» приложений
Когда говорят «Swift», многие сразу представляют себе очередное приложение для заказа кофе или фитнес-трекер. Но реальность куда интереснее. Этот язык давно вышел за рамки iOS-песочницы и используется в проектах, где на кону миллионы пользователей и миллиарды запросов в день. Uber, Airbnb, Lyft — это не просто имена, это живые примеры того, как Swift в реальных проектах решает нетривиальные задачи.
В этой статье мы разберем конкретные кейсы компаний, которые выбрали Swift не потому, что «модно», а потому что это было лучшим инженерным решением. Вы увидите не только сухие факты, но и примеры кода на Swift, которые можно адаптировать под свои задачи. Поехали!
Uber: как Swift спас производительность и читаемость кода
Один из самых ярких кейсов компаний на Swift — это история Uber. В 2016 году команда приняла волевое решение: переписать ключевые модули с Objective-C на Swift. Причина? Высокая частота падений приложения на старых устройствах и сложность поддержки legacy-кода.
Что именно переписали?
- Модуль геолокации и отображения карты
- Систему расчета стоимости поездки
- Интерфейс водителя (основной экран)
Главная боль была в том, что Objective-C не давал достаточной безопасности типов. Из-за этого ошибки всплывали только в рантайме, а не на этапе компиляции. Swift это исправил.
Пример кода: безопасная обработка опциональных значений
// До: Objective-C — можно передать nil и упасть
- (void)updatePrice:(NSNumber *)price {
if (price == nil) {
return; // забыли обработать — креш
}
self.priceLabel.text = [NSString stringWithFormat:@"$%.2f", [price floatValue]];
}
// После: Swift — компилятор не даст забыть
func updatePrice(_ price: Double?) {
guard let validPrice = price else {
print("Price is nil, showing placeholder")
return
}
priceLabel.text = String(format: "$%.2f", validPrice)
}
Результат: количество крешей снизилось на 35% за первые три месяца после релиза. Swift в реальных проектах показал, что безопасность типов — это не абстрактная фича, а деньги и нервы пользователей.
Airbnb: оптимизация работы с сетью и асинхронность
Airbnb — еще один гигант, который активно использует Swift. Но их история не про переписывание, а про построение с нуля. Когда команда решила создать новое приложение для хостов (Airbnb for Hosts), они сразу выбрали Swift.
Задача: работа с большим количеством изображений и заказов
Хосты загружают десятки фотографий, и каждую нужно сжать, обработать и отправить на сервер. В Objective-C это превращалось в «ад колбэков». Swift с его async/await сделал код линейным и понятным.
Пример кода: асинхронная загрузка изображений
import UIKit
struct ImageUploader {
func uploadImage(_ image: UIImage) async throws -> URL {
guard let imageData = image.jpegData(compressionQuality: 0.8) else {
throw UploadError.invalidImage
}
let url = URL(string: "https://api.airbnb.com/upload")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = imageData
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw UploadError.serverError
}
let json = try JSONDecoder().decode(UploadResponse.self, from: data)
return json.imageURL
}
}
enum UploadError: Error {
case invalidImage
case serverError
}
struct UploadResponse: Codable {
let imageURL: URL
}
Этот пример — классика разработки на Swift в современных проектах. Код читается как инструкция: «взяли изображение → сжали → отправили → получили URL». Никаких вложенных замыканий.
Lyft: производительность и работа с памятью
Lyft — прямой конкурент Uber, и их кейс использования Swift отличается. Они не переписывали всё целиком, а внедряли Swift постепенно, начиная с самых критичных по производительности модулей.
Проблема: утечки памяти в картах
Приложение Lyft интенсивно использует карты и анимации. В Objective-C утечки памяти были постоянной головной болью. Swift с его ARC (Automatic Reference Counting) и строгими правилами управления памятью решил эту проблему.
Пример кода: использование weak reference для избежания retain cycles
class MapViewController: UIViewController {
private var locationManager: CLLocationManager?
private var mapView: MKMapView?
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager?.delegate = self // Внимание: weak!
// Используем weak self в замыканиях
NotificationCenter.default.addObserver(
forName: UIApplication.didEnterBackgroundNotification,
object: nil,
queue: .main
) { [weak self] _ in
self?.stopUpdatingLocation()
}
}
private func stopUpdatingLocation() {
locationManager?.stopUpdatingLocation()
}
deinit {
NotificationCenter.default.removeObserver(self)
print("MapViewController deallocated")
}
}
extension MapViewController: CLLocationManagerDelegate {
// Реализация методов делегата
}
Обратите внимание на [weak self]. Без этого замыкание удерживало бы ViewController в памяти, даже если он уже закрыт. В Lyft такие паттерны используются повсеместно, и это один из ключевых примеров кода на Swift, который стоит взять на вооружение.
Неочевидный кейс: Swift на сервере (Vapor)
Когда говорят Swift в реальных проектах, редко вспоминают серверную сторону. А зря. Компания PlanetScale (система управления базами данных) использует Swift на бэкенде через фреймворк Vapor. Да, вы не ослышались: бэкенд на Swift.
Зачем?
- Единый язык для фронта и бэка — меньше переключения контекста
- Высокая производительность (близкая к Go и Rust)
- Безопасность типов на всем стеке
Пример кода: REST API на Vapor
import Vapor
final class UserController: RouteCollection {
func boot(routes: RoutesBuilder) throws {
let users = routes.grouped("api", "users")
users.get(use: index)
users.post(use: create)
users.group(":userID") { user in
user.delete(use: delete)
}
}
// GET /api/users
func index(req: Request) async throws -> [User] {
try await User.query(on: req.db).all()
}
// POST /api/users
func create(req: Request) async throws -> User {
let user = try req.content.decode(User.self)
try await user.save(on: req.db)
return user
}
// DELETE /api/users/:userID
func delete(req: Request) async throws ->