Комментарии 17
Я конечно не сварщик не swift программист, но хотел поинтересоваться, тестируют ли программы на Swift?
И как корректно тестировать статик синглтоны? Может на swift есть какая-то магическая изоляция глобального публичного состоятия?
И как корректно тестировать статик синглтоны? Может на swift есть какая-то магическая изоляция глобального публичного состоятия?
0
я пока в тестах неочень, возможно смогу чуть позже более развернуто ответить) спустя 3-6 месяцев) но пока такой задачи нет. Но вообще первое что гуглится stackoverflow.com/questions/8256989/singleton-and-unit-testing и medium.com/@martinrybak/how-to-mock-singletons-and-static-methods-in-unit-tests-cbe915933c7d буду смотреть в ту сторону если понадобится
0
И как корректно тестировать статик синглтоны?Не очень сварщик в плане того, что нечасто удается писать тесты. Но тестирование синглтона — мне не видится проблемой. Синглтон: обычный класс со статическим полем, в котором лежит предсозданный экземпляр. Можно тестировать этот уже готовый экземпляр, а можно — создать ещё экземпляры, и гонять тесты на них.
Другой вопрос — это тестирование кода, в котором происходит работа с синглтоном. Но опять же, если синглтон инъектить как зависимость закрытую протоколом, то класс, в который синглон инъектирован, тестируется так же как обычно.
То есть с точки зрения тестируемости, синглтон может быть вполне безвреден.
Что касается
изоляция глобального публичного состояния— тут, да, код выглядит довольно опасным. Все места в программе работающие с синглтоном будут работать с общим проперти dataArray, и если пользователь зачем-то начнёт работать с этим синглтоном из разных потоков, то начнется гонка за dataArray. Результатом станет емнип неопределенное поведение.
0
По моему мнению работа с веб-сокетами это своего рода компромисс который был создан с прицелом на веб-браузеры. Поэтому для нативных iOS/Android приложений перспективнее использовать транспорт tcp/tsl который поддерживают многие протоколы для работы с сообщениями например amqp, wamp или mqtt.
Единственное что можно поставить плюсом веб-сокетам для нативных приложений — это использование портов и протоколов https, которые обычно доступны и обычно не блокируются разными бранмауэрами или провайдерами сетевых услуг.
0
Можете подсказать зачем импортируется cfnetwork? Сколько не смотрел, не нашел его использование.
Ну и уточняющий момент: webSocketTask доступен начиная с айос13 в urlsession. Вы не поддерживаете предыдущие версии ос?
Ну и уточняющий момент: webSocketTask доступен начиная с айос13 в urlsession. Вы не поддерживаете предыдущие версии ос?
0
1. Для («wss://ТУТ_ВАШ_АДРЕС») сделать static переменную
2. «shared» менеджера объявить как private а методы менеджера — static; раз уж мы работаем с синглтоном. Меньше потом писать — чище код.
2. «shared» менеджера объявить как private а методы менеджера — static; раз уж мы работаем с синглтоном. Меньше потом писать — чище код.
0
1) Синглтон и свойство dataArray. Массив никак не освобождается, при каждом запросе данные добавляются и передаются из массива в комплишен. Рано или поздно, приложение ляжет намертво или будет ужасно тормозить. Это первый момент.
2) Второй момент. У вас подписка на тиковую историю, причем подписка не унифицирована и как явное значение передается в каждом методе. К примеру, если получать информацию по сотне инструментов, придется создать сотню методов на подписку и столько же на отписку. Почему не использовать дженерик и не унифицировать запрос?
3) Вы никак не обрабатываете обрыв соединения. С учетом того, что в случае синглтона, менеджер был инициирован однажды, по сути, он не может быть пересоздан. Я бы переписал пример без «вечного» объекта и эту строку вынес бы в конструктор:
4) Метод getData() содержит вот такой гард:
Зачем? Вызов произошел после загрузки вью. По сути, контроллер загружен и работает нормально. Внутри метода идет простая передача массива в свойство вашего контроллера.
2) Второй момент. У вас подписка на тиковую историю, причем подписка не унифицирована и как явное значение передается в каждом методе. К примеру, если получать информацию по сотне инструментов, придется создать сотню методов на подписку и столько же на отписку. Почему не использовать дженерик и не унифицировать запрос?
3) Вы никак не обрабатываете обрыв соединения. С учетом того, что в случае синглтона, менеджер был инициирован однажды, по сути, он не может быть пересоздан. Я бы переписал пример без «вечного» объекта и эту строку вынес бы в конструктор:
let webSocketTask = URLSession(configuration: .default).webSocketTask(with: URL(string: "wss://ТУТ_ВАШ_АДРЕС"*))
4) Метод getData() содержит вот такой гард:
guard let self = self else { return }
Зачем? Вызов произошел после загрузки вью. По сути, контроллер загружен и работает нормально. Внутри метода идет простая передача массива в свойство вашего контроллера.
self?.dataArray = ...
прекрасно отработает внутри метода. 0
А это под любыми версиями iOS работает? Мы пользовали cocoapods версию для вебсокетов как раз потому, что Apple только недавно добавила поддержку сокетов в свой SDK.
0
Самое интересное в Эппл реализации это то что надо в рекурсии вызывать
Я оставлю здесь пару ссылок где более развёрнуто описано как работать с новыми веб-сокетами:
1. appspector.com/blog/websockets-in-ios-using-urlsessionwebsockettask
2. kristaps.me/websockets-ios-13-swift
И понятно что это только для iOS 13. У меня вопрос, кто-нибудь пробовал использовать комбинацию
receiveData()
, но это надо делать только on .success
.Я оставлю здесь пару ссылок где более развёрнуто описано как работать с новыми веб-сокетами:
1. appspector.com/blog/websockets-in-ios-using-urlsessionwebsockettask
2. kristaps.me/websockets-ios-13-swift
И понятно что это только для iOS 13. У меня вопрос, кто-нибудь пробовал использовать комбинацию
Starscream
подключаемую как динамическую библиотеку для iOS 12- и встроенный для iOS13+. Есть какая-то выгода? По идеи памяти должно меньше кушать, ведь «все» системные либы динамические и скорее всего уже в памяти (случай для iOS13). Сама реализация думаю всем понятна, что надо написать обёртку для вебсокетов и менеджер который выбирает необходимую реализацию в зависимости от версии iOS. 0
Весь код сюда пихать не стану, лишь часть примера ради
Буквально на днях пилил себе такой менеджер.
Только для нашего сервера пришлось его сделать не на уровне простой URL, а через URL Request. Так появилась возможность использовать хеддер авторизации и дополнительный query в URL:
Плюс, для удобства сделал все на колбэках вместо делегата, в итоге конечное использование выглядит примерно так:
Делать синглтон из него не стал, так как используется только для одного экрана
Если кому надо полный код, могу запилить в гитхабе.
Если будут замечания, корректировки, буду рад принять
Буквально на днях пилил себе такой менеджер.
Только для нашего сервера пришлось его сделать не на уровне простой URL, а через URL Request. Так появилась возможность использовать хеддер авторизации и дополнительный query в URL:
final class WebSocket: NSObject {
private var urlSession: URLSession?
private var webSocketTask: URLSessionWebSocketTask?
init?(host: String, path: String, headers: [String: String], parameters: [String: String]) {
super.init()
urlSession = URLSession(configuration: .default,
delegate: self,
delegateQueue: nil)
var urlComponents = URLComponents()
urlComponents.scheme = "wss"
urlComponents.host = host
urlComponents.path = path
var items: [URLQueryItem] = []
for (key, value) in parameters {
let qItem = URLQueryItem(name: key, value: value)
items.append(qItem)
}
if items.count > 0 {
urlComponents.queryItems = items
}
guard let url = urlComponents.url else {
log.error("Could not create URL from components")
return nil
}
log.info("Socket URL: \(url.absoluteString)")
var request = URLRequest(url: url)
request.timeoutInterval = 30
headers.forEach { (key, value) in
request.addValue(value, forHTTPHeaderField: key)
}
webSocketTask = urlSession?.webSocketTask(with: request)
}
}
Плюс, для удобства сделал все на колбэках вместо делегата, в итоге конечное использование выглядит примерно так:
let websocket = WebSocket(host: server,
path: "/dash_wss",
headers: headers,
parameters: parameters)
websocket?
.connect()
.onConnected(callback: {
log.info("Socket connected")
})
.onDisconnected(callback: { (error) in
log.info("Socket disconnected with error: \(error?.localizedDescription ?? "No error")")
})
.onError(callback: { (error) in
log.error("Socket error \(error)")
})
.onTextMessage(callack: { (message) in
log.info("Socket message \(message)")
})
Делать синглтон из него не стал, так как используется только для одного экрана
Если кому надо полный код, могу запилить в гитхабе.
Если будут замечания, корректировки, буду рад принять
0
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.
Вариант работы с вебсокетами в iOS на языке Swift / Написал менеджер для работы с websocket