вторник, 11 августа 2015 г.

Trailing closure syntax in Swift

В Swift поддерживается удобная фича, видимо пришедшая из Perl : trailing closure syntax .
Допустим нам нужно отсортировать массив строк в лексикографическом порядке. Придумываем имена для двух переменных и сортируем:
searchResults.sort({ (result1: String, result2String) -> Bool in
    return result1.localizedStandardCompare(result2) == NSComparisonResult.OrderedAscending
})
Имена придуманных мною переменных я подсветил желтым. А вот более приятный глазу синтаксис:

searchResults.sort {   
    $0.name.localizedStandardCompare($1.name) == NSComparisonResult.OrderedAscending 
}
Вопрос читабельности остается открытом, на вкус и цвет как говорится...

понедельник, 10 августа 2015 г.

Методика отладки в XCode



  • Если приложение завершилось с ошибкой EXC_BAD_INSTRUCTION или SIGABRT,  отладчик Xcode обычно покажет сообщение об ошибке и место где эта ошибка случилась.
  • Если Xcode думает, что проблема находится в AppDelegate (не очень полезно!), включите Exception Breakpoint для получения большего количества информации.
  • Если приложение "падает" сигналом SIGABRT, но без сообщения об ошибке, тогда выключите Exception Breakpoint и дайте приложению "упасть" снова. (Или нажмите кнопку Continue program execution в откачки несколько раз. Это также покажет сообщение об ошибке.)
  • Ошибка EXC_BAD_ACCESS обычно означает, что что-то пошло не так с  memory management. Объект может быть “released” слишком много раз или  “retained” полностью. Со Swift эти проблемы большей частью остались в прошлом, потому что компилятор будет будет следить за этими вещами. Однако, все еще возможно получить эти ошибки если вы используете  Objective-C код или низкоуровневые API.
  • EXC_BREAKPOINT это не ошибка. Приложение останавливается в breakpoint  голубая стрелка указывает на ту линию где приложение приостанавливается. Вы устанавливаете breakpoints для того что бы поставить свое приложение на "паузу" в определенном месте кода, таким образом, что вы можете отслеживать состояние приложения в отладчике. Кнопка “Continue program execution” возобновляет работу приложения.
Это должно помочь решить большую часть проблем.

Проблема выделения ячейки UITableViewCell


Часто встречающаяся проблема при "тапе" на ячейку UITableViewCell , ячейка сохраняет свое выделение и остается выделенной до тех пор пока вы не выделите другую ячейку и т.д.
Для решения этой проблемы добавьте следующие методы в ваш UITableViewDelegate extension:
page29image17064
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRowAtIndexPath(indexPath, animated: true
}

func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {
    if searchResults.count == 0
        return nil
    } else {
        return indexPath

    } 

Как убрать промежуток над строкой поиска UISearchBar


Часто разработчик не знаетт как убрать уродливый промежуток над строкой поиска. Приложение выглядит намного лучше если строка состояния (status bar) имеет тот же стиль, что и строка поиска (search bar)

Для решения этой проблемы добавьте в ваш класс (являющийся SearchBarDelegate) следующий метод:


func positionForBar(bar: UIBarPositioning) -> UIBarPosition 
    return .TopAttached

Если вы будете искать этот метод в API документации для UISearchBarDelegate protocol, то вы его не найдете. Все потому что этот метод принадлежит протоколу UIBarPositioningDelegate , который расширяется протоколом UISearchBarDelegate (как и классы, протоколы могут наследовать друг другу).

Как в iOs скрыть клавиатуру жестом

В storyboard, выберите Table View. Идите Attributes inspector и установите значение Keyboard в Dismiss interactively




Программное задание границ (edges) UITableView

tableView.contentInset = UIEdgeInsets(top: 64, left: 0, bottom: 0, right: 0)

суббота, 8 августа 2015 г.

Установка фокуса на элемент при открытии View

Для установки фокуса на элементе необходимо вызвать метод becomeFirstResponder()  этого элемента. 
Пример:
textField.becomeFirstResponder()

Для установки фокуса при каждом открытии View (см. подробней View Lifecycle) необходимо переопределить метод viewWillAppear .
Пример:
override func viewWillAppear(animated: Bool) { 
    super.viewWillAppear(animated) 
    textField.becomeFirstResponder() 
    // ваш код...

пятница, 7 августа 2015 г.

Background Threads

И так, начнем с простого. Мы ставим перед собой задачу: перемещаться "в" и "из" фоновый поток.
И сразу натыкаемся на легкий случай - синтаксис не слишком отличается от Objective-C. В первом приближении это выглядит так:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
 // do some task
 dispatch_async(dispatch_get_main_queue(), ^{
  // update some UI
 });
});
Единственное заметное отличие - то, что код на Swift может использовать замыкания за пределами параметров функции (ориг.: trailing closures), исключая необходимость в закрытии родительских скобок в конце:
let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(dispatch_get_global_queue(priority, 0)) {
 // do some task
 dispatch_async(dispatch_get_main_queue()) {
  // update some UI
 }
}


Совет: Для того чтобы сказать, в какой потоке выполняется конкретный кусок кода (в главном или нет), добавьте следующий код:
println("On the main thread? " + (NSThread.currentThread().isMainThread ? "Yes" : "No"))

Если используя Swift,  вы часто сталкиваетесь со следующей ситуацией: вы делаете что-то в фоне и по окончанию работы в фоновом потоке вам нужно что-то выполнить в главном потоке (например обновить UI или tableView.reloadData() и т.д. ), то вам может пригодиться умный оператор от Josh Smith:
{ /* do some task */ } ~> { /* update some UI */}
Вот демонстрация





















Более полная демонстрация возможностей для оператора ~> здесь .

Оригинал: https://thatthinginswift.com/background-threads/

суббота, 1 августа 2015 г.

Swift observers


Ниже приведен пример willSet и didSet в действии. В примере определен новый class, названный StepCounter, который отслеживает полное количество шагов пройденное пользователем. 

class StepCounter {
   var totalSteps: Int = 0 {
       willSet(newTotalSteps) {
           println("About to set totalSteps to \(newTotalSteps)")
       }
       didSet {
           if totalSteps > oldValue {
               println("Added \(totalSteps - oldValue) steps")
           }
       }
   }
}

Документация: