Задача

Итак, наша задача создать iOS приложение, в среде разработки Xcode,  в котором будет всплывающее окно —Pop Up View, при этом все что сзади этого окна будет затемняться. Подобный прием использован во многих приложениях, но я не смог найти информацию как именно это сделать — насколько нужно затемнять, сколько времени должна идти анимация и пр.

В итоге, я сделал этот Pop Up View на свой вкус. Читатели смогут самостоятельно изменить параметры всплывающего окна и подстроить их на свое усмотрение.

После выполнения задачи у нас получится такое приложение:

 

(далее…)

Пример использования библиотеки Alamofire

Задача: создать iOS приложение в среде разработки Xcode 9 на языке программирования Swift 4, которое посылает HTTP запрос, а в ответ получает данные, которые обрабатывает и отображает в виде таблицы. После разработки у нас получится такое приложение.

Для запроса данных мы будем использовать стороннюю библиотеку Alamofire. Alamofire — это свободно распространяемая, библиотека с открытым исходным кодом, благодаря которой работа с сетью (любые запросы, отправка и получения файлов, скачивание картинок и пр.) упрощается до написания нескольких строк. Думаю, если вы пытались разрабатывать iOS приложения, в которых используются стандартные классы от Apple, особенно, если вы  начинающий программист, — вы были немного озадачены набором классов и надстроек для совершения простого GET запроса. С помощью Alamofire код становится более элегантный и понятный для чтения.

(далее…)

Метки: ,

Пример и памятка по основным командам LLDB для работы с breakpoint — точками останова.

(далее…)

Метки:

Основные команды Terminal и начало работы в LLDB
(далее…)

Если в процессе разработки iOS приложения или любого другого приложения потребуется выяснить какое количество памяти используется в данный момент, то можно использовать следующую функцию:

//
// proSwift.ru
//

func report_memory() {
    var info = mach_task_basic_info()
    var count = mach_msg_type_number_t(MemoryLayout<mach_task_basic_info>.size)/4
    
    let kerr: kern_return_t = withUnsafeMutablePointer(to: &info) {
        $0.withMemoryRebound(to: integer_t.self, capacity: 1) {
            task_info(mach_task_self_,
                      task_flavor_t(MACH_TASK_BASIC_INFO),
                      $0,
                      &count)
        }
    }
    
    if kerr == KERN_SUCCESS {
        print("Memory in use (in bytes): \(info.resident_size)")
    }
    else {
        print("Error with task_info(): " +
            (String(cString: mach_error_string(kerr), encoding: String.Encoding.ascii) ?? "unknown error"))
    }
}

Попробуем в деле нашу функцию. Только я использовал для удобного отображения размера памяти еще и разделитель триад из предыдущей статьи.

//
// proSwift.ru
//

print("Memory in use (in bytes): \(info.resident_size.formattedWithSeparator)")

Выполним цикл, в котором сто раз создадим массив из случайного числа, а также каждый шаг цикла будем вызывать написанную нами функцию report_memory()

//
// proSwift.ru
//

for i in 1...100 {
    let n = [arc4random_uniform(999999)]
    report_memory()
}

Моя консоль выглядит так:

Memory in use (in bytes): 36 950 016
Memory in use (in bytes): 36 954 112
Memory in use (in bytes): 36 966 400
Memory in use (in bytes): 36 978 688
Memory in use (in bytes): 36 982 784
Memory in use (in bytes): 36 990 976
Memory in use (in bytes): 37 003 264
Memory in use (in bytes): 37 011 456
Memory in use (in bytes): 37 019 648
Memory in use (in bytes): 37 027 840
Memory in use (in bytes): 37 031 936
Memory in use (in bytes): 37 044 224
Memory in use (in bytes): 37 052 416
Memory in use (in bytes): 37 060 608
Memory in use (in bytes): 37 072 896
Memory in use (in bytes): 37 076 992
Memory in use (in bytes): 37 097 472
Memory in use (in bytes): 37 105 664
Memory in use (in bytes): 37 117 952

 




 

Метки: ,

Без долгих вступлений и СЕО-якорей — сразу к делу.
Для того чтобы добавить разделитель триад к любым числовым значениям нужно написать два расширения — одно для класса Formatter, а второе для числового типа, например Int или UInt32.

(далее…)

Метки:

Шаблон autoreleasepool используется в Swift при возврате объектов autorelease (созданных либо вашим кодом Objective-C, либо использованием классов Cocoa). autorelease в Swift функционирует так же, как в Objective-C. Для примера можно рассмотреть метод создания объектов NSImage / UIImage:

//
// proSwift.ru
//

func useManyImages() {
    let filename = pathForResourceInBundle

    for _ in 0 ..< 5 {
        autoreleasepool {
            for _ in 0 ..< 1000 {
                let image = NSImage(contentsOfFile: filename)
            }
        }
    }
}

Если запустить из Инструментов Activity Monitor, то можно увидеть график использования памяти:

Но если вы сделаете это без autoreleasepool, вы увидите, что пиковое использование памяти выше:

 

Autoreleasepool позволяет вам явно управлять освобождением памяти, когда объекты autorelease деинициализирутся в Swift, так же, как и в Objective-C.

Примечание. При работе с объектами Swift вы, как правило, не будете получать объекты autorelease. Вот почему в начале статьи упоминается оговорка о том, что это нужно только при «работе с Objective-C». Но если вы имеете дело с объектами Objective-C (включая классы Cocoa), они могут быть объектами autorelease, и в этом случае это Swift-представление шаблона Objective-C @autoreleasepool по-прежнему полезно.




Метки:

FlatMap против nil

Если функция (метод или инициализатор) может вернуть nil, а мы будем использовать эту функцию в качестве преобразователя в .map, то можно сразу отсеять элементы nil и вернуть не опциональные элементы

//
//  proSwift.ru
//

class Event {
    init?(...) {
        ...
        return someValue

        else ...
        return nil
    }
}

objects.map(Event.init) // [obj1?, obj2?, nil, obj4?, nil, nil, obj6?]

objects.flatMap(Event.init) // [obj1, obj2, obj4, obj6]

Вызовы Event.init могут вернуть nil, а flatMap на этих объектах удалит любые значения nil, поэтому на выходе мы получим объекты Event (не опциональные!)

Лог потоков

Вывод в консоль лога по потокам:

//
//  proSwift.ru
//

print("main: \(Thread.isMainThread)") // Проверка - это основной поток?
print("Thread: \(Thread.current)") .  // Вывод данных о потоке

Консоль:

main: true
Thread: <NSThread: 0x608000077680>{number = 1, name = main}

...

main: false
Thread: <NSThread: 0x608000274ac0>{number = 3, name = (null)}




Reduce для Observable

//
//  proSwift.ru
//

example(of: "reduce") { 
    let source = Observable.of(1,2,3,4,5,6)
    let obs = source.reduce(0, accumulator: +) // выдаст элемент только когда source закончится.
    obs.subscribe(onNext: { print($0) })
}

Reduce (_: _ 🙂 создает сводное (накопленное) значение только тогда, когда завершается исходный наблюдаемый. Применение этого оператора к последовательностям, которые никогда не завершатся, не испускает ничего. Это частый источник путаницы и скрытых проблем

Метки:

Зачем все это нужно?

Обработка ошибок во время выполнения программы и самое главное — реакция приложения на эти ошибки — это хорошая практика для любого программного продукта. Согласитесь, если вы пользуетесь приложением и в какой-то момент оно без каких либо видимых проявлений «падает»,  — что вы подумаете  про разработчика? Думается — ничего хорошего. А ведь можно в коде добавить обработчики ошибок, и в читабельном формате сообщать пользователю что именно пошло не так. С одной стороны — это значительно повышает юзабилити приложения, с другой облегчает отладку при разработке.

Однако, ошибки не всегда нужно обрабатывать. Языковые функции  Swift позволяют избежать некоторых ошибок в целом. Как правило, если вы можете избежать возникновения ошибки, возьмите именно этот путь проектирования и разработки мобильного приложения iOS. Но если вы не можете избежать потенциального условия появления ошибки, то явная обработка — лучший вариант.

 

В этой статье я составлю памятку по работе с ошибками на языке программирования  Swift 3

(далее…)

Тернарный условный оператор

Проверку на выполнение условий можно записать со помощью условного оператора if else

//
// proSwift.ru
//
// Swift 3

if batteryLow {
    replaceBattery()
} else {
    plugAndPlay()
}

Тут все просто — если батарейки сели — нужно их заменить, а если они в порядке — то можно и  использовать. Эту конструкцию можно записать в одну строку.

//
// proSwift.ru
//
// Swift 3

batterylow ? replaceBattery() : plugAndPlay()

Эти два выражения абсолютно равнозначны.

Оператор ??

//
// proSwift.ru
//
// Swift 3

let result = optional ?? defaultValue

Оператор ?? применяется к опциональному значению optional, и если оно извлекается то в result вернется извлеченное значение. А если значение не извлекается, т.е. оно равно nil, то вернется значение defaultValue. Это сокращение следующей конструкции

//
// proSwift.ru
//
// Swift 3

if optional != nil {
    return optional!
} else {
    return defaultValue
}

// Или в сокращенном варианте 

optional != nil ? optional! : defaultValue


 



Метки:
Сайт размещается на хостинге Спринтхост