MPM
Посмотреть все сим-линки в системе
find / -type l -ls
Посмотреть все изменёёные файлы за последние N минут
find . -type f -mmin -30
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 } }
Очередь
protocol QueueProtocol { associatedtype Element mutating func append(element: Element) mutating func next() -> Element? }
Реализация очереди:
struct Queue<E>: QueueProtocol { typealias Element = E var elements: [E] = [] mutating func append(element: E) { elements.append(element) } mutating func next() -> E? { if elements.first == nil { return nil } return elements.removeFirst() } }
Пример применения очереди:
var queue = Queue<Int>() queue.append(element: 1) queue.append(element: 2) queue.append(element: 3) queue.append(element: 4) while let e = queue.next() { print("E -> \(e)") }
git: сохранение в stash по имени
сохранение в stash с названим/комментарием
git stash save "some message "
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.
Использование реактивщины в iOS приложениях на Xamarin
- Через NuGet подключаем в проект пакет ReactiveUI
- Прописываем там где нам надо
using ReactiveUI;
- Подписываемся на события
inputText.EditingChanged += (object sender, EventArgs e) => { Console.WriteLine("Editing value changed"); };
Вибрация в приложении
Самый быстрый способ добавить вибрацию в приложение
import AudioToolbox ... AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate)) // vibration ...
Задчака на понимание
Что будет напечатано после выполнения кода ?
var foo: Bool { print("Вы нам") return false } var bar: Bool { print("не") return true } if foo && bar { print("нравитесь") } else { print("подходите") }
Паттерны GRASP
Паттерны «общей ответственности»
- Information Expert
- Creator
- Controller
- Low Coupling
- High Cohesion
- Polymorphism
- Pure Fabrication
- Indirection
- Protected Variations
Zinc Scanner
Сканер штрих кодов партий готовой продукции
Стек: Swift, MVVM, AVFoundation, RxRealm, Moya(REST), GCD
Описание формата SMILES
Описание формата SMILES
SMILES — Simply Molecule in Line-entering Structure
Условные обозначения
символ | описание |
= | двойная связь |
# | тройная связь |
$ | четыри связи |
\ | хиральная связь |
: | — aromatic bond symbol |
/ | — ??? |
Запахи кода
Раздувальщики
- Длинный метод
- Большой класс
- Одержимость элементарными типами
- Длинный список параметров/аргументов
- Группы данных
Утяжелители изменений
- Расходящиеся модификации
- Стрельба дробью
- Параллельные иерархии классов
Замусориватели
- Комментарии
- Дублирование кода
- Ленивый класс
- Класс данных
- Мёртвый код
- Теоретическая общность
Опутыватели связями
- Завистливые функции
- Неуместная близость
- Цепочка вызовов
- Посредник
Методы рефакторинга
Временные абстрации
Временную переменную заменяем на вызов метода (выделение метода)
Предпосылки к рефакторингу
Код повторяется
Метод слишком велик
Цикл слишком велик или слишком глубоко вложен в другие циклы
Класс имеет плохую связность
Интерфейс класса не формирует согласованную абстракцию
Метод принимает слишком много параметров
Отдельные части класса изменяются независимо от других частей
При изменении программы требуется параллельно изменять несколько классов
Вам приходится параллельно изменять несколько иерархий наследования
Вам приходится параллельно изменять несколько блоков case
Родственные элементы данных, используемые вместе, не организованы в классы
Метод использует больше элементов другого класса, чем своего собственного
Элементарный тип данных перегружен
Класс имеет слишком ограниченную функциональность
По цепи методов передаются бродячие данные
Объект посредник ничего не делает
Один класс слишком много знает о другом классе
Метод имеет неудачное имя
Данные члены сделаны открытыми
Подкласс использует только малую долю методов своих предков
Сложный код объясняется при помощи комментариев
Код содержит глобальные переменные
Перед вызовом метода выполняется подготовительный код (после вызова метода выполняется код «уборки»)
Программа содержит код, который может когда нибудь понадобиться
О Haskell по-человечески
«Функциональное программирование — своеобразное гетто посреди мегаполиса нашей индустрии. Доля функциональных языков пока ещё очень мала, и многие разработчики побаиваются знакомства с этими языками, и с Haskell в особенности.
Вероятно, вы слышали, что Haskell — это что-то архисложное, сугубо научное и непригодное для реальной жизни? Читайте дальше, и вскоре вы убедитесь в обратном.»
Маленькая памятка по созданию реактивной переменной
Подключаем реактивный свифт
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
Vuex
Vuex — это паттерн управления состоянием и библиотека для приложений на Vue.js. Он служит центральным хранилищем данных для всех компонентов приложения и обеспечивает предсказуемость изменения данных при помощи определённых правил.
Getters
Функции возвращающие значения из store. Используйте их, когда над значениями в store надо произвести какие то действия прежде чем передать их вызвавшему. (Вы так же можете считывать напрямую.)
Mutations
Функции которые коммитят изменения в store. Могут быть использованы для пред-обработки значений перед сохранением. Вы так же можете изменять state напрямую
Actions
Функции похожие на мутации. исключая коммиты данных во время асинхронных таксов. Они не являются обязательными, но вы должны привыкнуть использовать их всякий раз, когда присутствуют мутации.
Жизненный цикл Vuex (Life Cycle)
пример использования Getters
<template> <div> <div>Value = {{ getMyProperty }}</div> <div>Value = {{ getStoredProp }}</div> </div> </template> <script> import { mapGetters } from 'vuex'; export default { computed: { ...mapGetters([ 'getMyProperty' ]), // or, without helper... getStoredProp: () => { return this.$store.getters.getMyProperty; } } } </script>
пример использования Mutations
<template> <div> <button @click="setMyProperty(22)">Set to 22</button> <button @click="setThatProp(0)">Reset to 0</button> </div> </template> <script> import { mapMutations } from 'vuex'; export default { methods: { ...mapMutations([ 'setMyProperty' ]), // Or without helper... setThatProp( value ) { this.$store.commit( 'setMyProperty', value ); } } } </script>
пример использования Actions
<template> <div> <button @click="doChangeMyProperty(5)">Change me to 5</button> </div> </template> <script> import {mapActions} from 'vuex'; export default { methods: { ...mapActions([ 'doAsyncChangeMyProperty', ]), // Or without helper... doThatThing( value ) { this.$store.dispatch('doAsyncChangeMyProperty', value); } } } </script>
двусторонний биндинг
<template> <div> <input type="text" v-model="my_property"/> {{ my_property }} </div> </template> <script> export default { computed: { my_property: { get() { return this.$state.getters.my_property; }, set( value ) { this.$state.dispatch('setMyProperty', value); } } } } </script>
On Store Object
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); export const store = new Vuex.Store({ state: { my_property: 47 }, getters: { getMyProperty: state => { return state.my_property; } }, mutations: { setMyProperty: ( state, payload ) => { state.my_property = payload; } }, actions: { doChangeMyProperty: ( context, payload ) => { context.commit('setMyProperty', payload); }, doAsyncChangeMyProperty: ( { commit }, payload ) => { // Using a timeout, but any async operation can go here setTimeout(function () { commit('setMyProperty', payload); }, 1000); } } });
On Modules
const moduleA = { state: { ... }, mutations: { ... }, actions: { ... }, getters: { ... } } const moduleB = { state: { ... }, mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB } }) store.state.a // moduleA's state store.state.b // moduleB's state