Новое:Talanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

+666новых вакансий за сутки·52 265вакансий открыто сейчас·Новое:Talanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

Новые вакансии в TelegramРаботодателям
Talanto
Вакансии
Компании5 686
РезюмеAIПодготовкаСтатьи
ТарифыТарифы
Войти

Не нашли подходящее?

Пусть нужная вакансия найдёт вас сама.

  1. Подборка в TelegramНовые вакансии по вашему фильтру — сразу в бота.Подключить
  2. Мэтчи по резюмеЗагрузите резюме — покажем, где вы подходите лучше всего.Загрузить
  3. Сохранить фильтрНастройте поиск один раз и возвращайтесь к новым вакансиям.Настроить
Что нового на TalantoTalanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

Для работодателей

Опубликуйте вакансию — отклики придут в ваш кабинет.

  1. Вакансиябесплатно
  2. Откликиконтакты бесплатно
  3. Наймэтапы и интервью

40 компаний публикуют вакансии напрямую · 4 394 кандидата открыты к предложениям

Разместить вакансию

Популярные направления

Все подборки
  • Python5 973
  • Облачные технологии4 523
  • QA вакансии1 689
  • Android1 143
  • Инженер данных788
  • Продакт-менеджер308

Разработка

  • iOS1 093
  • Backend вакансии1 020
  • Fullstack вакансии448
  • AI вакансии378
  • Frontend вакансии369
  • Mobile вакансии27

По стеку

  • Go3 345
  • Java2 037
  • Kotlin908
  • Node.js746
  • Rust492
  • .NET481
  • PHP278
  • C++213
  • C#199

DevOps и инфраструктура

  • Kubernetes2 562
  • Linux-инфраструктура2 030
  • DevOps вакансии1 855
  • Terraform / IaC1 548
  • CI/CD876
  • Мониторинг и Observability709
  • SRE229
  • Кибербезопасность40

Аналитика и данные

  • Аналитик данных479
  • Data Scientist443
  • Бизнес-аналитик342
  • Системный аналитик50

Другие направления

  • Проджект-менеджер107
  • UI/UX дизайн70
  • Ручное тестирование14

По регионам

  • Вакансии в США24 039
  • Вакансии в Европе9 373
  • Работа в России2 968
  • Вакансии в Канаде2 114

По формату

  • Удалённые вакансии41 595
  • Релокация в США24 039
  • Гибридная работа5 209
  • Офисная работа3 834

По уровню

  • Senior вакансии22 591
  • Middle вакансии12 174
  • Junior вакансии4 013

Сейчас нанимают

Все компании
  • Rakuten189 вакансий
  • ASML163 вакансии
  • Grab134 вакансии
  • Wise81 вакансия
  • Infobip28 вакансий
  • Darktrace17 вакансий
  • Spotify17 вакансий
  • Celonis14 вакансий
  • UiPath13 вакансий
  • Adyen9 вакансий

Вакансии из 344 источников: карьерные страницы компаний и джоб-борды.

КомпанииО насНовостиПубличная офертаУсловия использованияПолитика конфиденциальностиПоддержка
←К теме SwiftUIВсе вопросы
SwiftUIJuniorКодинг

Как реализовать пользовательский ViewModifier в SwiftUI?

В закладки
Сначала попробуйте ответить сами30 секунд
Сравнить с ответом ↓

Создайте структуру, реализующую протокол ViewModifier с методом body(content:), возвращающим модифицированный Content. Применяйте через .modifier(MyModifier()) или через расширение View с удобным методом.

Протокол ViewModifier

ViewModifier — это протокол SwiftUI, позволяющий инкапсулировать и переиспользовать группу модификаторов. Вместо того чтобы копировать цепочку .padding().background().cornerRadius() в каждый view, вы описываете её один раз в структуре-модификаторе.

Протокол требует реализовать единственный метод:

func body(content: Content) -> some View

Параметр content — это placeholder, представляющий view, к которому применяется модификатор.

Базовый пример

import SwiftUI

// 1. Описываем модификатор
struct CardStyle: ViewModifier {
    var cornerRadius: CGFloat = 12
    var shadowRadius: CGFloat = 4

    func body(content: Content) -> some View {
        content
            .padding(16)
            .background(Color(.systemBackground))
            .cornerRadius(cornerRadius)
            .shadow(color: .black.opacity(0.1), radius: shadowRadius, x: 0, y: 2)
    }
}

// 2. Расширение View для удобного вызова
extension View {
    func cardStyle(
        cornerRadius: CGFloat = 12,
        shadowRadius: CGFloat = 4
    ) -> some View {
        modifier(CardStyle(
            cornerRadius: cornerRadius,
            shadowRadius: shadowRadius
        ))
    }
}

// 3. Использование
struct ProfileCard: View {
    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            Text("Иван Петров")
                .font(.headline)
            Text("iOS разработчик")
                .font(.subheadline)
                .foregroundColor(.secondary)
        }
        .cardStyle(cornerRadius: 16)
    }
}

Модификатор с @State (собственное состояние)

ViewModifier может хранить собственное состояние через @State — это делает его полноценным компонентом:

struct ShakeEffect: ViewModifier, Animatable {
    var shakes: CGFloat = 0

    var animatableData: CGFloat {
        get { shakes }
        set { shakes = newValue }
    }

    func body(content: Content) -> some View {
        content
            .offset(x: sin(shakes * .pi * 2) * 10)
    }
}

extension View {
    func shake(trigger: Bool) -> some View {
        modifier(ShakeEffect(shakes: trigger ? 3 : 0))
    }
}

// Использование с анимацией
struct LoginView: View {
    @State private var wrongPassword = false

    var body: some View {
        TextField("Пароль", text: .constant(""))
            .shake(trigger: wrongPassword)
            .onTapGesture {
                withAnimation(.easeInOut(duration: 0.4)) {
                    wrongPassword.toggle()
                }
            }
    }
}

Модификатор с Environment

struct AdaptiveText: ViewModifier {
    @Environment(\.colorScheme) private var colorScheme

    func body(content: Content) -> some View {
        content
            .foregroundColor(colorScheme == .dark ? .white : .black)
            .font(.system(size: 16, weight: .medium, design: .rounded))
    }
}

extension View {
    func adaptiveText() -> some View {
        modifier(AdaptiveText())
    }
}

Условное применение модификатора

extension View {
    @ViewBuilder
    func `if`<Transform: View>(
        _ condition: Bool,
        transform: (Self) -> Transform
    ) -> some View {
        if condition {
            transform(self)
        } else {
            self
        }
    }
}

// Использование
Text("Важно!")
    .if(isHighlighted) { view in
        view.foregroundColor(.red).bold()
    }

Разница между ViewModifier и прямым расширением View

Прямое расширение View возвращает some View и не имеет собственного состояния. ViewModifier — полноценная структура, которая может:

  • хранить @State, @Environment, @Binding
  • реализовывать Animatable для кастомных анимаций
  • содержать @ViewBuilder-параметры для добавления дочерних view
  • быть передана как значение (modifier(someModifier))

Подводные камни

  • Порядок применения модификаторов важен: .padding().background() и .background().padding() дают разный результат — padding включается в фон или нет.
  • Нельзя использовать модификатор до инициализации view: ViewModifier применяется к уже существующему content, нельзя изменить тип или структуру исходного view.
  • @State в модификаторе сбрасывается при пересоздании родителя: если родительский view пересоздаётся с новой structural identity, модификатор тоже пересоздаётся и теряет состояние.
  • Производительность условных модификаторов: паттерн .if(_:transform:) с @ViewBuilder меняет тип view при изменении условия — SwiftUI трактует это как разные view, что нарушает анимации переходов.
  • Именование конфликтует с системными методами: если назвать расширение так же, как встроенный модификатор (например, .padding()), компилятор может не выбрать нужную перегрузку.
  • Нельзя возвращать несколько корневых View из body: метод body(content:) должен возвращать одно view — используйте Group или VStack при необходимости объединить несколько элементов.

Частые вопросы на собеседовании

  • Как SwiftUI перерисовывает (re-render) представления и что вызывает обновление view?
  • В чём разница между @State, @Binding, @ObservedObject и @StateObject?
  • Как async/await интегрируется с представлениями SwiftUI через модификатор .task?
  • Как работает NavigationStack в SwiftUI и чем он отличается от NavigationView?

Типичные ошибки

  • Сводить «реализовать пользовательский ViewModifier в SwiftUI» к синтаксису и не объяснять инвалидация body.
  • Игнорировать жизненный цикл, основной поток или момент освобождения ресурсов в сценарии swiftui-16.
  • Выбирать API по привычке, не проверяя состояние, ошибки, доступность и платформенные ограничения.

Что проверяет интервьюер

  • Формулирует точную модель для «реализовать пользовательский ViewModifier в SwiftUI» и подтверждает ее корректным примером.
  • Умеет связать ответ с navigation state, тестированием и отладкой на устройстве.
  • Называет ограничения подхода swiftui-16, включая производительность, память и сопровождение.

Как вы знаете этот вопрос?

Проверить себя по теме SwiftUI →

Источники

  • https://developer.apple.com/documentation/swiftui/viewmodifier
←Предыдущий вопросКакие production-риски есть у SwiftUI: memory, lifecycle bugs, accessibility, offline mode, app size или platform-specific behavior?Следующий вопрос→Как тестировать SwiftUI-представления?

Связанные темы

SwiftUIimplementation-reasoningMobile-Engineeringui-rendering-performance