• Как сделать локальные уведомления по расписанию на Swift?

    maestrro712
    @maestrro712
     iOS Developer
    Вы уже практически сделали все, что было нужно. Осталось несколько штрихов.

    1. Сейчас функция scheduleNotification создаёт нотификации с одним и тем же id. Новые нотификации перетирают старые. Лучше в качестве id использовать или константы, или что-то связанное с заголовком: "\(content.title.hash)".
    2. Текст надо вынести в параметры функции:
    func scheduleNotification(inSeconds seconds:TimeInterval, text: String, completion: (Bool) -> ())
    . Тогда можно будет его использовать для создания нотификации: content.title = text.
    3. deinit нужно убрать совсем. Он удаляет вашу нотификацию при удалении экрана из памяти.
    4. Если нужно ставить нотификации без нажатия кнопки, то можно использовать метод viewDidLoad() из этого же класса.
    Ответ написан
    2 комментария
  • Связывание view model с view controller используя замыкания. Корректен ли данный подход в MVVM?

    maestrro712
    @maestrro712
     iOS Developer
    У меня был опыт использования MVVM без реактивщины. Немного длиннее код, но в целом нормально. Большая часть реактивщины избыточна, если вам нужен только байндинг.

    Что касается конкретно этого кода, то все таки в парадигме MVVM не надо связывать действие пользователя с результатом. То есть у вас есть отдельно метод deleteFood(IndexPath) и отдельно
    var animatableChanges: ((OldData, NewData) -> Void)?
    куда View может засунуть свой байндинг. Такой подход позволяет ViewModel обновлять вьюху тогда, когда она посчитает нужным, а с другой стороны держать код всех байндингов в одном месте (к примеру, в специальном методе, вызываемом из viewDidLoad).
    Ответ написан
    4 комментария
  • Как перезагрузить Webview только после того как страница загружена?

    maestrro712
    @maestrro712
     iOS Developer
    Я думаю, это можно сделать, отменяя загрузку в методе делегата и делая ее вручную:
    func webView(_ webView: WKWebView,
                     decidePolicyFor navigationAction: WKNavigationAction,
                     decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
            URLSession.shared.dataTask(with: navigationAction.request) { [weak webView] (data, _, _) in
                decisionHandler(.cancel)
                guard let html = data.flatMap({ String(data: $0, encoding: .utf8) }) else {
                    return
                }
                webView?.loadHTMLString(html, baseURL: navigationAction.request.url)
            }.resume()
        }

    Естественно в такой ситуации надо тщательно проработать всяческие граничные условия, к примеру редиректы.
    Ответ написан
    Комментировать
  • Какая реальная автономность Macbook Pro 13" 2017 без тачбара?

    maestrro712
    @maestrro712
     iOS Developer
    Имею опыт использования двух таких машин:
    1) Жена около года юзает самую простую машинку из линейки. Без подзарядки может использовать его весь день (часов 6-8 точно). Задачи офисного плана, но при весьма небрежном отношении к ресурсам: по два браузера с 20+ вкладок, несколько открытых документов word/excel, куча вкладок в preview, несколько мессенджеров и тд. Спустя где-то 8-9 месяцев после покупки начал туго нажиматься пробел, остальные клавиши живут нормально пока.
    2) Сам получил на работе такую прошку в топовой конфигурации без тачбара (core i7, 16 gb ram) месяц с небольшим назад. Работаю в основном от розетки, полностью сажать батарею не доводилось. Могу сказать, что час активной работы в xcode + несколько девелоперских тулов (симулятор, zeplin, charles, postman) сажают батарею на 10-15%. Скорость работы меня более чем устраивает. Удивительно, что при одинаковом объеме оперативки и меньшей частоте процессора (2.5 против 3), этот ноутбук собирает мой рабочий проект в 1,5 раза быстрее, чем предыдущий мак.
    Ответ написан
    Комментировать
  • Как распространяются и передаются приложения iOS, если я хочу отдать клиенту на проверку?

    maestrro712
    @maestrro712
     iOS Developer
    Вам нужно сделать следующее:

    1. Получить от клиента UDID его устройств (можно почитать здесь: whatsmyudid.com )
    2. Зарегистрировать эти айдишники на developer.apple.com (Account > Certificates,identifiers&profiles > Devices)
    3. Там же в разделе Provisioning profiles поменять профиль, под которым вы собираете приложение, поставив галочки напротив нужных устройств
    4. Скачать и установить профиль (просто двойной щелчок мыши, откроется xcode, но ничего вам не скажет)
    5. В окне экспорта (на вашем скриншоте) выбрать Ad Hoc и экспортировать с новым профилем
    Ответ написан
    Комментировать
  • Как отследить состояние textField?

    maestrro712
    @maestrro712
     iOS Developer
    UITextField наследуется от UIControl, а значит вы можете подписываться на его controlEvents. Пример:

    override func viewDidLoad() {
            super.viewDidLoad()
            textField.addTarget(self, action: #selector(editingBegan(_:)), for: .editingDidBegin)
            textField.addTarget(self, action: #selector(editingChanged(_:)), for: .editingChanged)
            textField.addTarget(self, action: #selector(editingEnded(_:)), for: .editingDidEnd)
        }
    
        @objc func editingBegan(_ textField: UITextField) {
            //пользователь попал в поле, но еще ничего не ввел
        }
    
        @objc func editingChanged(_ textField: UITextField) {
            //текст изменился
        }
    
        @objc func editingEnded(_ textField: UITextField) {
            //ввод окончен, к примеру нажали "return" на клавиатуре
        }
    Ответ написан
    1 комментарий
  • Как сделать фотографию программно, не вызывая камеру?

    maestrro712
    @maestrro712
     iOS Developer
    Это можно сделать, но только когда приложение активно. Работу с камерой надо вести через AVFoundation. Тема довольно сложная, чтобы ее сейчас расписывать, погуглите "AVFoundation capture session"
    Ответ написан
    Комментировать
  • За что платит AdMob в итоге?

    maestrro712
    @maestrro712
     iOS Developer
    Оплата идет за клики. Но тк разные клики стоят по разному и являются очень случайным явлением, AdMob нигде не пишет, сколько вы получили за каждый конкретный клик (хотя само число кликов можно посмотреть) - только общую сумму за день/неделю/месяц и тд. Рекомендуется все же ориентироваться на CPM (стоимость 1000 показов), которая высчитывается на основе общего дохода и общего числа показов. Подразумевается, что если нет никаких искусственных манипуляций мошенничества, эта величина рапределяется уже более равномерно и больше подходит для оценки и прогнозов.
    Ответ написан
    Комментировать
  • Как правильно реализовать UIPasteboard.general.string + actionSheet?

    maestrro712
    @maestrro712
     iOS Developer
    очень просто :) заведите "white list" для ссылок:

    1. Заводим простой Set, который хранится в вашем экземпляре AppDelegate
    2. Для UIAlertAction, который соответсвует кнопке cancel, добавляем action:
    self.whiteList.insert(link)
    3.Прежде, чем показать UIAlertController, проверяем white list:
    guard !whiteList.contains(link) else {
       return
    }
    let alertController = ...
    Ответ написан
  • Как перебрать массив словарей в swift?

    maestrro712
    @maestrro712
     iOS Developer
    К сожалению вы неверно подобрали структуру данных. Ваша проблема в том, что ваш код не перебирает словари, а перебирает содержимое внутри словаря. Тут надо знать, что порядок записей в словаре не гарантируется. То есть когда на месте HomeTeam и GuestTeam окажутся реальные данные, вы никак не сможете определить кто есть кто.
    Я не знаю источника выших данных и где они еще используются, но чисто под эту задачу рекомендовал бы такую структуру:

    typealias ResultsArray = [[(homeTeam: (name: String, score: String), guestTeam: (name: String, score: String))]]
    
    //для сравнения, ваша структура:
    typealias YourStructure = [[[String: String]]
    Ответ написан
    1 комментарий
  • Почему происходит ошибка разворачивания инициализированного опционала,?

    maestrro712
    @maestrro712
     iOS Developer
    Я вижу 2 случая, когда переменная не инициализируется:

    1. `fetch` произошел с ошибкой. Ошибка поймалась в `catch`, исполнение счастливо пошло дальше, но `per2` так и осталась не инициализированной
    2. массив `fetchResult` - пустой, тогда тело цикла не выполнится ни разу
    Ответ написан
    4 комментария
  • Как обратиться из своего класса к классу ViewController для изменения IBOutlet или вызова методов?

    maestrro712
    @maestrro712
     iOS Developer
    Описываемый вами подход не самый удачный. ViewController неспроста так называется, именно он управляет всем view и его содержимым, соответственно, изменять свойства у IBOutlet'а должен только он. Чтобы избежать соблазна, лучше сразу декларировать все IBOutlet как private.
    Вместо вашего подхода лучше сделать так, чтобы ViewController был оповещен о произошедших изменениях и соответствующе апдейтил свой view. Сделать это можно многими способами, вот лишь некоторые из них:

    1) У вашего класса логики есть делегат. ViewController в методе viewDidLoad находит экземпляр вашего класса и назначает себя делегатом:

    class ViewController: NSViewController {
        
        @IBOutlet private weak var usernameLabel: NSTextField!
    
        func viewDidLoad() {
            super.viewDidLoad()
            let someInstance = //тут мы находим ваш экземляр (к примеру, он синглтон)
            someInstance.delegate = self
        }
    }
    
    extension ViewController: SomeInstanceDelegate {
        func updateUsernameOnUI(_ username: String) {
            usernameLabel.stringValue = username
        }
    }


    2) Ваш класс логики может оповещать своих обзерверов и ViewController становится обзервером:

    class ViewController: NSViewController {
        
        @IBOutlet private weak var usernameLabel: NSTextField!
    
        func viewDidLoad() {
            super.viewDidLoad()
            let someInstance = //тут мы находим ваш экземляр (к примеру, он синглтон)
            someInstance.addObserver(self)
        }
    }
    
    extension ViewController: SomeInstanceObserver {
        func usernameUpdated(_ username: String) {
            usernameLabel.stringValue = username
        }
    }


    3) Если никак не получается при инициализации связать класс логики и ViewController (что, в общем, не гуд), можно использовать NotificationCenter:

    class ViewController: NSViewController {
        
        @IBOutlet private weak var usernameLabel: NSTextField!
    
        func viewDidLoad() {
            super.viewDidLoad()
            NotificationCenter.default.addObserver(self, selector: #selector(usernameUpdate(:)), 
                                                                           name: Notification.Name("usernameUpdated"), object: nil)
        }
    }
    
    extension ViewController {
        @objc func usernameUpdate(_ notification: Notification) {
            guard let username = notification.userInfo?["username"] as? String else {
                  return
            }
            usernameLabel.stringValue = username
        }
    }
    Ответ написан
    Комментировать
  • Как реализовать фоновое выполнение задач?

    maestrro712
    @maestrro712
     iOS Developer
    У iOS приложений весьма жесткий подход к background режиму. Для ваших задач действительно подходит Background fetch. Однако есть 2 момента:

    1. система сама выбирает переодичность запуска приложения. Вы можете повлиять на ее "предпочтения", делая запрос как можно быстрее, и возвращая сообщение, что вы скачали новые данные.
    2. приложение, которое пользователь убил руками (выкинул из трея) не будет запускаться для фетча совсем.

    Из-за всего этого, правильный подход - когда сервер оповещает приложение по средствам пушей, а не приложение само проверяет данные.
    Ответ написан
    Комментировать
  • Как выложить приложение для ios если Apple пишет ошибка 2.1 нет ipv6?

    maestrro712
    @maestrro712
     iOS Developer
    ваш хостинг должен поддерживать ipv6, без этого в стор сейчас не попасть. Кроме того, проверьте, что все сетевые адреса должны быть забиты через доменные имена, а не ip
    Ответ написан
  • Как реализовать Auto-Renewable в iOS?

    maestrro712
    @maestrro712
     iOS Developer
    Все 4 пункта вам поможет сделать онлайн-валидация чека покупки. Вкратце это выглядит так:

    1. Приложение получает у iOS чек прилоложения (receipt). При получении его желательно обновить.
    2. Приложение отправляет receipt на ваш сервер.
    3. Ваш сервер делает запрос в AppStore с этим receipt и shared secret.
    4. AppStore возвращает вам json, в котором есть информация о всех покупках в этом приложении пользователя с этим Apple id.
    5. В полученной информации нас интересуют:
    а) original_purchase_date - дата оформления подписки
    б) purchase_date - дата последней оплаты
    в) is_trial_period - показывает, что пользователь пользует пробный период
    г) cancellation_date - если не равно null, покупка была отменена
    6. PROFIT!

    Подробно процесс по шагам описан здесь: https://developer.apple.com/library/content/releas...
    Ответ написан
    1 комментарий
  • Кто как мокирует в swift, и как тестировать сервисы?

    maestrro712
    @maestrro712
     iOS Developer
    В рантайме создать mock невозможно в свифте к сожалению :( более того, поведение структуры нельзя никак изменить. Поэтому мы используем 2 вещи:

    1. Зависимости везде указываются через протоколы
    2. Моки нельзя подсунуть в рантайме, но можно генерить на этапе сборки с помощью Sourcery. Эта тула помогает генерировать код автоматически по темплейтам.
    Ответ написан
    5 комментариев
  • Какие актуальные размеры макетов, дизайна приложений для iOS и для Android?

    maestrro712
    @maestrro712
     iOS Developer
    для iOS сейчас основной макет обычно рисуют в 375х675 @2x, тк большинство вновь покупаемых телефонов сейчас -это 6/6S/7. Если есть ресурсы, желательно еще иметь макеты в 320x568 @2x и 414x736 @3x
    Ответ написан
    1 комментарий
  • Как в ios сделать, чтобы ссылка на альбом/фото/запись и т.п. в вк открывалась в приложении вк, а не в браузере?

    maestrro712
    @maestrro712
     iOS Developer
    замените протокол http на vk, т.е. vk://vk.com/.... должно заработать. Минус в том, что если приложение не стоит, то ссыль не откроется вообще. В этом плане логичнее выглядит ссылка на специальную страницу, которая попробует открыть ссылку на приложение и в случае неудачи заредиректит на сайт
    Ответ написан
    2 комментария
  • Как исправить ошибку при обновлении приложения?

    maestrro712
    @maestrro712
     iOS Developer
    У вас есть основное приложение, у него свой bundle. Судя по всему, у вас также есть какие-то дополнительные продукты, упакованные в ваше приложение - наборы стикеров, приложение для часов, виджеты и тп. Так вот у каждого из них свой bundle. Названия всех этих бандлов не должны совпадать. К примеру, если у приложения com.iamcool.coolapp, то у виджета должен быть, к примеру, com.iamcool.coolapp.widget
    Ответ написан
    Комментировать
  • Как адаптивно Верстать ios приложения?

    maestrro712
    @maestrro712
     iOS Developer
    Про xamarin не скажу, в нативной разработке используются NSLayoutConstraint и Size Classes. У Apple есть замечательный документ: https://developer.apple.com/library/content/docume...
    Ответ написан
    Комментировать