Swift
Итерация по enum
enum State { case none case one case two }
Конформим State под протокол CaseIterable
extension State: CaseIterable {}
После этого мы можем итерироваться
State.allCases.forEach { print($0) }
Интересные Callback'и
Объявляем тип для callback замыкания
typealias RegStateCallbackType = @convention(c) (_ accountId: pjsua_acc_id) -> Void
var onRegStateCallback: RegStateCallbackType?
И можно тогда заюзать следующим образом
endpointCfg.cb.on_reg_state = onRegStateCallback
Swift String to C char *
void mi_connect_device(char *device_name);
func connect(to device: String) { device.withCString { let int8Pointer = UnsafeMutablePointer<Int8>(mutating: $0) mi_connect_device(int8Pointer) } }
RxSwift кастомная View'ха
Пишем своё расширение кастомной вьюхи.
import UIKit import RxSwift import RxCocoa class CustomControl: UIControl { var value: Int = 0 { didSet { sendActions(for: .valueChanged)} } override init(frame: CGRect) { super.init(frame: frame) } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } func toggle() { if value == 0 { backgroundColor = .green value = 1 } else { backgroundColor = .red value = 0 } } } extension Reactive where Base: CustomControl { var value: ControlProperty<Int> { return base.rx.controlProperty(editingEvents: UIControlEvents.valueChanged, getter: { customView in return customView.value }, setter: { customView, newValue in customView.value = newValue }) } }
И теперь использовать можно так
customView.rx.value .subscribe(onNext: { value in print("changed my value -> \(value)") }) .disposed(by: bag)
Login screen
Реализовал Login screen на VIPER, хотя в несколько облегчённом варианте, скорее всего ещё допилю взаимодействие между модулями. Router — > Router + Presenter
VIPER
V — View (Views + ViewControllers)
I — Interactor — бизнес логика модуля
P — Presentor (ViewModels and prepare)
E — Entities — (Models)
R — Router
Swift KVO
Модель
import Foundation @objc class Card: NSObject { @objc dynamic var life: Int = 0 @objc dynamic var atack: Int = 0 @objc dynamic var defense: Int = 0 }
Задаём переменную для invalidate()
var cardObserver: NSKeyValueObservation?
Подписываемся на изменения и вешаем обработчик
let card = Card() cardObserver = card.observe(\Card.life, options: .old, changeHandler: { card, change in print("Changed life value \(card.life) -> ", change.oldValue ?? -1) })
Соответсвенно когда мы меняем значение переменной `life` то вызывается наш обработчик
card.life = 12 card.life = 1 card.life = 34
Swift: setTimeOut
DispatchQueue.main.asyncAfter(deadline: .now() + 0.600) { // some code }
Swift
Разница между датами
func calcDiff(between start: String, and end: String ) -> String { if let endTime = Date.from(end), let startTime = Date.from(start) { return Calendar.current.date(from: Calendar.current .dateComponents([.hour, .minute], from: startTime, to: endTime))? .formatted("HH:mm") ?? "--:--" } printError("Can't convert time ") return "--:--" }
Collection with safe index
extension Collection where Indices.Iterator.Element == Index { subscript(safe index: Index) -> Iterator.Element? { return indices.contains(index) ? self[index] : nil } }
Dependency Injection
Dependency Injection или DI.
Описание протокола и вариантов зависимости
protocol DependencyProtocol { func makeMoney() -> Float } class Alfa: DependencyProtocol { func makeMoney() -> Float { return 100; } } class Betta: DependencyProtocol { func makeMoney() -> Float { return 9000; } }
class Wallet { var sourceMoney: DependencyProtocol init(source: DependencyProtocol) { sourceMoney = source } getMoney() -> Float { return sourceMoney.makeMoney() } }
Использование
let myWallet = Wallet(source: Betta()) var myMoney = myWallet.getMoney()
Weak против Unowned
В Swift эти модификаторы ссылок схожи, но не одинаковы
Weak | Unowned | |
Слабая ссылка | Да | Да |
Увеличивает счётчик ссылок для ARC | Да | Нет |
Пример использования weak
Нельзя помечать weak протоколы не относящиеся к ссылочному типу
Пример использования unowned
class BaseService { unowned let provider: ServiceProviderProtocol init(provider: ServiceProviderProtocol) { self.provider = provider } }
Желаю всем более обдуманного выбора при использовании weak и unowned.
Вибрация в приложении
Самый быстрый способ добавить вибрацию в приложение
import AudioToolbox ... AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate)) // vibration ...
Маленькая памятка по созданию реактивной переменной
Подключаем реактивный свифт
import RxSwift
Создаём «сумку» для мусора, при деините объекта все ссылки из этой сумки будут корректно зачищены
let bag = DisposeBag()
Инитим переменную и её наблюдатель
var reactiveVariable = Variable<Int>(1) var nabludatel = PublishSubject<Int>()
...
reactiveVariable.asObservable() .bind(to: nabludatel) .disposed(by: bag) nabludatel.asObservable() .bind { print("called when changed var -> \($0)") } .disposed(by: bag)
Применяем
reactiveVariable.value = 31337
Статья о lldb
Debugging Swift code with LLDB
ll Debug
https://medium.com/flawless-app-stories/debugging-swift-code-with-lldb-b30c5cf2fd49
Хранимые переменные в экстеншенах
Stored properties in swift extensions
protocol PropertyStoring { associatedtype T func getAssociatedObject(_ key: UnsafeRawPointer!, defaultValue: T) -> T } extension PropertyStoring { func getAssociatedObject(_ key: UnsafeRawPointer!, defaultValue: T) -> T { guard let value = objc_getAssociatedObject(self, key) as? T else { return defaultValue } return value } } protocol ToggleProtocol { func toggle() } enum ToggleState { case on case off } extension UIButton: ToggleProtocol, PropertyStoring { typealias T = ToggleState private struct CustomProperties { static var toggleState = ToggleState.off } var toggleState: ToggleState { get { return getAssociatedObject(&CustomProperties.toggleState, defaultValue: CustomProperties.toggleState) } set { return objc_setAssociatedObject(self, &CustomProperties.toggleState, newValue, .OBJC_ASSOCIATION_RETAIN) } } func toggle() { toggleState = toggleState == .on ? .off : .on if toggleState == .on { // Shows background for status on } else { // Shows background for status off } } } let a = UIButton() print(a.toggleState) a.toggleState = .on print(a.toggleState)
Источник: https://marcosantadev.com/stored-properties-swift-extensions/
RxAlamofire + SwiftyJSON
import RxAlamofire import SwiftyJSON func load() { let host = "http://chemnote.ru/api/v1/periodic/" guard let url = host.url else { return } RxAlamofire.requestJSON(.get, url) .bind { (r, json) in let dic = JSON(json) for (_,element) in dic { let symbol: String = element["symbol"].stringValue PeriodicTable.elements.append(Element(with: symbol)) print("el: \(symbol) ") } } .disposed(by: bag) }
md5 на swift
import CryptoSwift extension String { func md5() -> String { let bytes:Array<UInt8> = Array(self.utf8) let md5hash = bytes.md5().toHexString() return md5hash } }
Printable
extension Element: CustomStringConvertible { var description : String { return "element: \(symbol)" } }