Всем привет! Меня зовут Сергей, моё основное направление — мобильные приложения, но помимо этого я пристально наблюдаю за тем, что происходит с ИИ.
Недавно мы все увидели новость:
10 апреля «Яндекс» представил «Алису нового поколения» — и про-подписку, где собраны продвинутые функции.
Не задумываясь, я сразу оформил подписку и решил попробовать, что же это такое.
В своей работе я часто использую сервис ChatGPT, но это не всегда удобно, особенно из-за необходимости включать VPN. Давайте попробуем ответить на вопрос: может ли разработчик мобильных приложений, например на платформе iOS, использовать Yandex GPT в своей ежедневной работе?
Небольшое отступление. Как я понимаю, в этом году все компании по всему миру в срочном порядке ищут способы монетизации ИИ-сервисов, так как все понимают, что это "круто", но пока неясно, где деньги =)
Итак, заходим на https://a.ya.ru
Помощь с кодом
Представим, что мы мобильные разработчики, которые каждый день пишут на языке Swift. Мы хотим использовать YaGPT ежедневно в своей работе. Для этого проверим его компетентность по сравнению с GPT 4o от компании OpenAI.
Наше собеседование на роль AI-ассистента будет проходить в три этапа:
Алгоритмическая сессия. Дадим несколько задачек с leetcode.
Исправление кода. Дадим небольшой кусочек кода и попросим его улучшить.
Теоретические вопросы. Попробуем задать несколько теоретических вопросов.
Берем первую задачку с уров��ем "просто" с leetcode

Переводим текст задачи на русский, чтобы было честно, все же работаем с YaGPT
Текст промпта
Задача
Дан массив целых чисел nums и целое число target. Верните индексы двух чисел таким образом, чтобы их сумма была равна target.
Вы можете предполагать, что каждый ввод имеет ровно одно решение, и вы не можете использовать один и тот же элемент дважды.
Вы можете вернуть ответ в любом порядке.
Пример 1:
Ввод: nums = [2,7,11,15], target = 9
Вывод: [0,1]
Пояснение: Поскольку nums[0] + nums[1] == 9, мы возвращаем [0, 1].
Пример 2:
Ввод: nums = [3,2,4], target = 6
Вывод: [1,2]
Пример 3:
Ввод: nums = [3,3], target = 6
Вывод: [0,1]
Ограничения:
2 <= длина массива nums <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
Существует только один правильный ответ.
Начальный код
class Solution {
func twoSum(_ nums: [Int], _ target: Int) -> [Int] {}
}
Получаем результаты
YaGPT

Проверяем ответ в leetcode

А теперь сравним с решением ChatGPT 4o

Ответ от GPT 4o оказался более оптимизированным, но в целом обе сети справились с решением.
Давайте возьмем еще одну задачку для проверки
Текст промпта
Дано целое число x. Вернуть true, если x является палиндромом, и false в противном случае. Целое число является палиндромом, когда оно читается одинаково как слева направо, так и справа налево. Например, 121 является палиндромом, в то время как 123 не является палиндромом.
Пример 1: Ввод: x = 121 Вывод: true
Пояснение: 121 читается одинаково слева направо и справа налево.
Пример 2: Ввод: x = -121 Вывод: false
Пояснение: Слева направо оно читается как -121. Справа налево оно становится 121-. Поэтому это не палиндром.
Пример 3: Ввод: x = 10 Вывод: false
Пояснение: Справа налево оно читается как 01. Поэтому это не палиндром.
Ограничения: -2^31 <= x <= 2^31 - 1
Начальный код class Solution { func isPalindrome(_ x: Int) -> Bool { } }
Пробуем

Пробуем отправить код на проверку и видим ошибку к сожалению =(

Проверяем код, который отдает GPT 4o. Результаты говорят сами за себя

Исправление кода
Дадим небольшой кусочек кода и попросим его улучшить.
Примечание
Изначально я не знал, что у YaGPT есть ограничение на количество символов. Когда я начал проверять его, я подумал, что можно заменить задачу на более простую. Но задача с версткой очень базовая, и действительно ИИ может помочь в этом. Поэтому я решил не менять задачу и о��тавить ее как есть.
Давайте предположим что у вас есть вот такой экран в приложении

И тут к вам приходят, и говорят а нужно заменить текст. Вы говорите, конечно, задачка на две минуты. И заменяете текст и видите следующее.

Экран поехал, никто не предполагал, что там будет столько текста. Скролла, конечно же, нет. Что нужно сделать? Правильно, нужно добавить скролл на данный экран, чтобы все элеме��ты могли скролиться, но кнопку "Поделиться" давайте оставим фиксированной за пределами скролла. Итак, попробуем отправить эту задачку в Алису и в GPT.
Текст промпта
import UIKit
import SnapKit
class ViewController: UIViewController {
let headerBlockView: UIView = {
let view = UIView()
view.backgroundColor = .lightGray
return view
}()
let linkContainerView: UIView = {
let view = UIView()
view.backgroundColor = .lightGray
view.layer.cornerRadius = 10
return view
}()
let referralLinkLabel: UILabel = {
let label = UILabel()
label.text = "https://google.com"
label.textColor = .systemBlue
label.numberOfLines = 1
label.textAlignment = .center
return label
}()
let copyButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("Copy", for: .normal)
button.addTarget(self, action: #selector(copyLink), for: .touchUpInside)
return button
}()
let shareButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("Поделиться", for: .normal)
button.setTitleColor(.white, for: .normal)
button.backgroundColor = .red
button.layer.cornerRadius = 10
button.addTarget(self, action: #selector(shareLink), for: .touchUpInside)
return button
}()
let descriptionLabel: UILabel = {
let label = UILabel()
label.text = """
Искусственный интеллект (ИИ) о потенциал уже сейчас меняет мир, открывая новые возможности во всех сферах нашей жизни. ИИ способен анализировать огромные объемы данных за считанные секунды, находя в них закономерности и выводы, которые были бы недоступны человеку. Это приводит к улучшению решений в медицине, финансах, производстве и других областях.
"""
label.numberOfLines = 0
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 14)
return label
}()
let agreementLabel: UILabel = {
let label = UILabel()
label.text = """
Нажимая "Поделиться", ты соглашаешься с правилами программы.
"""
label.numberOfLines = 0
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 12)
label.textColor = .gray
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setupUI()
}
func setupUI() {
view.addSubview(headerBlockView)
view.addSubview(linkContainerView)
linkContainerView.addSubview(referralLinkLabel)
linkContainerView.addSubview(copyButton)
view.addSubview(descriptionLabel)
view.addSubview(shareButton)
view.addSubview(agreementLabel)
headerBlockView.snp.makeConstraints { make in
make.top.equalTo(view.safeAreaLayoutGuide.snp.top)
make.leading.trailing.equalToSuperview()
make.height.equalTo(200)
}
linkContainerView.snp.makeConstraints { make in
make.top.equalTo(headerBlockView.snp.bottom).offset(16)
make.leading.trailing.equalToSuperview().inset(16)
make.height.equalTo(50)
}
referralLinkLabel.snp.makeConstraints { make in
make.centerY.equalTo(linkContainerView.snp.centerY)
make.leading.equalTo(linkContainerView.snp.leading).offset(16)
}
copyButton.snp.makeConstraints { make in
make.centerY.equalTo(linkContainerView.snp.centerY)
make.leading.equalTo(referralLinkLabel.snp.trailing).offset(8)
make.trailing.equalTo(linkContainerView.snp.trailing).inset(16)
}
descriptionLabel.snp.makeConstraints { make in
make.top.equalTo(linkContainerView.snp.bottom).offset(16)
make.leading.trailing.equalToSuperview().inset(16)
}
shareButton.snp.makeConstraints { make in
make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-16)
make.leading.trailing.equalToSuperview().inset(16)
make.height.equalTo(50)
}
agreementLabel.snp.makeConstraints { make in
make.bottom.equalTo(shareButton.snp.top).offset(-8)
make.leading.trailing.equalToSuperview().inset(16)
}
}
@objc func copyLink() {
UIPasteboard.general.string = referralLinkLabel.text
let alert = UIAlertController(title: "Copied", message: "Referral link copied to clipboard.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
present(alert, animated: true, completion: nil)
}
@objc func shareLink() {
let activityVC = UIActivityViewController(activityItems: [referralLinkLabel.text ?? ""], applicationActivities: nil)
present(activityVC, animated: true, completion: nil)
}
}
Положи все объекты на скрол вью, чтобы все элементы скролились так как в label может быть много текста
Кнопка поделится должна быть над scollview чтобы она не скролиласьЧто у нас получилось с GPT 4o
Пробуем использовать YaGPT, и к сожалению видим ограничению по вводимому тексту, и весь экран у нас не помещается в ответ(даже половина)
Ничего, подумал я. Давайте попрбуем зайти в Yandex Cloud, возможно там нет такого ограничения на ввод. Но нет, к сожалению мы видим такое же ограничение.

По итоге в этом тесте ставим YaGPT минус.
Теоретический вопрос
Попробуем задать базовый вопрос про работу с памятью в swift ИИ
Вопрос
Расскажи как в swift работать с памятью
YaGPT
В Swift управление памятью осуществляется через два основных механизма:
Automatic Reference Counting (ARC) и Manual Memory Management.Automatic Reference Counting (ARC)ARC является предпочтительным
и дефолтным механизмом управления памятью в Swift.
Он автоматизирует процесс выделения и освобождения памяти, упрощая работу
разработчика.
ARC отслеживает количество сильных ссылок на объекты и освобождает память,
когда количество ссылок становится равным нулю.Manual Memory ManagementНесмотря на то,
что ARC является основным механизмом управления памятью в Swift, иногда требуется более точный контроль над выделением и освобождением памяти.
Для этого используются технологии вроде UnsafeMutablePointer и UnsafeBufferPointer,
которые позволяют напрямую управлять памятью.
Пример работы с памятью в SwiftРассмотрим пример использования
ARC:class
University {
var title: String
init(title: String) {
self.title = title
print("\(title) has been initialized.")
}
deinit {
print("\(title) has been deallocated.")
}
}
func assignTitle() {
_ = University(title: "Cambridge")
}
assignTitle()
В этом примере создается класс University с одним свойством title типа String. При создании экземпляра класса University с помощью метода init печатается сообщение о инициализации объекта. После того как экземпляр выходит из области видимости, вызывается метод deinit, который печатает сообщение о деинициализации объекта.Этот пример демонстрирует, как ARC автоматически управляет памятью, освобождая ее после того, как экземпляр класса University выходит из области видимости.GPT 4o
Работа с памятью в Swift в основном управляется автоматически с помощью механизма ARC (Automatic Reference Counting). Однако, чтобы эффективно использовать память и избегать проблем, таких как утечки памяти и циклические ссылки, важно понимать, как ARC работает и как управлять ссылками на объекты. Вот подробное руководство по работе с памятью в Swift:
### Основные концепции ARC
#### Сильные ссылки (Strong References)
По умолчанию все ссылки на объекты являются сильными. Это означает, что объект будет удерживаться в памяти до тех пор, пока на него существует хотя бы одна сильная ссылка.
```swift
class Person {
var name: String
init(name: String) {
self.name = name
}
}
var john: Person? = Person(name: "John") // Сильная ссылка на объект Person
```
#### Слабые ссылки (Weak References)
Слабые ссылки не удерживают объект в памяти. Они используются, чтобы избежать циклическ��х ссылок. Слабые ссылки объявляются с помощью ключевого слова `weak`.
```swift
class Apartment {
weak var tenant: Person?
}
class Person {
var name: String
var apartment: Apartment?
init(name: String) {
self.name = name
}
}
var john: Person? = Person(name: "John")
var unit4A: Apartment? = Apartment()
john?.apartment = unit4A
unit4A?.tenant = john
john = nil // Объект Person освобождается, так как единственная сильная ссылка на него установлена в nil
```
#### Несоблюдающие ссылки (Unowned References)
Несоблюдающие ссылки (`unowned`) также не удерживают объект в памяти, но в отличие от слабых ссылок они предполагают, что объект всегда будет существовать при обращении к нему. Несоблюдающие ссылки используются, когда обе стороны взаимосвязи всегда существуют одновременно.
```swift
class Customer {
var creditCard: CreditCard?
init() {
self.creditCard = CreditCard(customer: self)
}
}
class CreditCard {
unowned let customer: Customer
init(customer: Customer) {
self.customer = customer
}
}
var customer = Customer()
// customer имеет сильную ссылку на creditCard, а creditCard имеет несоблюдающую ссылку на customer
```
### Избегание циклических ссылок
Циклические ссылки возникают, когда два объекта удерживают друг друга, создавая цикл. Это приводит к утечкам памяти, так как ARC не может освободить такие объекты. Использование слабых и несоблюдающих ссылок помогает избежать циклических ссылок.
#### Пример циклической ссылки
```swift
class Person {
var name: String
var apartment: Apartment?
init(name: String) {
self.name = name
}
}
class Apartment {
var tenant: Person?
}
var john: Person? = Person(name: "John")
var unit4A: Apartment? = Apartment()
john?.apartment = unit4A
unit4A?.tenant = john
john = nil // john и unit4A не освобождаются из памяти из-за циклической ссылки
```
#### Исправление циклической ссылки с использованием слабых ссылок
```swift
class Apartment {
weak var tenant: Person?
}
// Остальная часть кода остается без изменений
```
### Управление памятью с помощью замыканий (Closures)
Замыкания в Swift захватывают ссылки на любые переменные и объекты, которые они используют внутри себя. Это может привести к циклическим ссылкам, если замыкание и захваченные объекты ссылаются друг на друга.
#### Пример замыкания, создающего циклическую ссылку
```swift
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name) is being deinitialized")
}
}
var heading: HTMLElement? = HTMLElement(name: "h1", text: "Hello, world!")
print(heading!.asHTML())
heading = nil // HTMLElement не освобождается из памяти
```
#### Использование захватывающих списков (Capture Lists) для предотвращения циклических ссылок
```swift
lazy var asHTML: () -> String = { [weak self] in
guard let self = self else { return "" }
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
```
### Вывод
Работа с памятью в Swift с помощью ARC позволяет автоматизировать управление памятью и уменьшить количество ошибок, связанных с ручным управлением памятью. Однако важно понимать, как работают сильные, слабые и несоблюдающие ссылки, чтобы эффективно предотвращать утечки памяти и избегать циклических ссылок.Выводы делайте сами =)
Итог
Очень круто, что у нас создаются такие продукты, как YandexGPT и Gigachat. Они определенно движутся в правильном направлении. Но, к сожалению, как инструменты для разработчиков, которые можно использовать уже сейчас, они пока не подходят.
А используете ли вы ИИ в своей работе?
Если вам интересно больше узнать об ИИ, подписывайтесь на мой телеграм‑канал.
