32 заметки с тегом

Objective-C

Swift Array Subrange: Slice

В работе над одним интересным проектом мне понадобились разные подмножества элементов одного массива. Для этого у массивов в Свифте есть метод subscript, в который кроме конкретного индекса можно передавать диапазон значений.

let deliciousDuck = rotissomat[2]
let anyOtherDucks = rotissomat[12...85]

В действительности же, это два разных метода:

subscript (index: Int) -> T
subscript (subRange: Range<Int>) -> Slice<T>

Метод, который принимает диапазон, возвращает подмножество данных типа Slice. Например:

let range: Range<Int> = 1..<3 // 2 elements

let ducks:   Array<String> = ["Huey", "Dewey", "Louie"]
let lastTwo: Slice<String> = ducks[range]

В документации Свифта уточняется, что Slice всегда использует область памяти, «смежную» с исходным массивом, и не бриджится в Обджектив-Си.

(Что такое ротиссомат? :-)

2015   code   Objective-C   Swift

Size Classes

В конце августа, на ежемесячной встрече разработчиков приложений для iOS и OS X CocoaHeads Moscow, я рассказывал про новую концепцию Size Classes, представленную Эплом на WWDC-2014. Это совершенно новый способ построения адаптивных интерфейсов для айос-дивайсов. Немного коснулся интересных тонкостей о том, как их использовать в приложениях на айос-8, и как их бекпортить на айос-6.

Встреча традиционно проходила в офисе Мейл-ру. Там точно была видеозапись и, кажется, даже трансляция. У меня пока этой записи нет, но вот слайды с презентации:

Очень интересно, какие вопросы появятся у читателей моего блога. Буду рад ответить :)

На этой встрече также докладывал Михаил Байнов про массивы и структуры ANSI C/C99, и Саша Зимин рассказывал материальный дизайн кнопок из нового Андроида-Л и показывал как это сделать на Свифте; с его презентации также доступны слайды.

Upd. Видеозапись доклада: http://blog.m4rr.ru/all/size-classes-addition/

2014   CocoaHeads   iOS   Objective-C   Swift   Xcode

Как не показывать эмоджи в UILabel

Мы с другом сейчас работаем над одним очень интересным проектом, который выйдет осенью, вместе с Айос-8. И в этом проекте появилась задача: показать некоторые стандартные юникодные значки. Но, оказывается, если эти символы добавить в UILabel, то айось заменит их на картинки-эмоджи. Это, конечно, круто, но не то, что нам нужно.

Emoji UILabel

Я ничего не знал о том, как работают эмоджи, поэтому пришлось провести небольшой рисерч. Оказывается, в юникоде есть такая штука как variation selector. Он документирован в стандарте с 3.2.0, а сейчас уже — 6.0.

variation sequence, which always consists of a base character followed by the variation selector, may be specified as part of the Unicode Standard. That sequence is referred to as a variant of the base character. The variation selector affects only the appearance of the base character,* and only in the variation sequences defined in this Standard. The variation selector is not used as a general code extension mechanism.
Источники: раз, два.

Итак, variation sequence — последовательность, которая состоит из базисного символа и следующего за ним модификатора (variation selector). Такая последовательность ссылается на вариацию базисного символа. Модификатор влияет только на внешний вид символа.

Таким образом, юникодный символ, для которого существует эмоджи-картинка, мапится в эмоджи. Но существует такой модификатор U+fe0e, который, будучи добавленным к юникодному символу форсит выбор не-эмоджи варианта символа.

Короче, можем написать любой символ (U+2709 — для конверта), и к нему U+fe0e:

// Swift:
label.text = "Привет, посылаю тебе ✉︎\u{fe0e} не из этой страны"
// Objective-C:
label.text = @"Привет, посылаю тебе \U00002709\U0000FE0E не из этой страны";

И получить то, что нужно:

Non-emoji UILabel

(Кстати, есть еще кодировка эмотиконов Softbank, которая используется в смс. В опенсорсе на сайте Эпла есть таблица их мапинга в эмоджи и обратно: Any_SoftbankSMS.txt)

2014   Objective-C   Swift   Unicode   Xcode

Как поставить кнопки друг к другу

Иногда в интерфейсе айос-приложений нужно расставить кнопки друг к другу, чтобы ширина у всех автоматически стала одинаковой, как, например, в старом добром Тотал-командере:

Кнопки Тотал-коммандера

Некоторые рекомендуют использовать Auto Layout в разработке только когда это действительно нужно. Но, очевидно, это самый удобный способ сделать хороший интерфейс со связанными между собой элементами.

С появлением Size Classes в iOS 8, становится понятно, что любой другой способ получается слишком громоздким. Поэтому, задача расставления кнопок (UIButton или вообще любой UIView) сводится к правильной расстановке констрейнтов автолейаута.

Решение, вроде, простое на первый взгляд: нужно в Интерфейс-билдере сделать все кнопки одного размера, поставить их друг к другу, и привязать левую границу каждой кнопки к правой границе предыдущей кнопки. А левую и правую границы крайних — привязать к супервьюхе. И с первого подхода выходит вот такая фигня:

Damn auto layout!

Делаем второй подход, чтобы пофиксить это. Нужно задать всем вьюхам, что их ширины равны:

Good auto layout.

Ура!

2014   Objective-C   Swift   Xcode

Как удалить все сабвьюхи

Как известно, в Какао вьюхе нельзя послать сообщение для удаления всех сабвьюх. Так делать небезопасно. Но Обджектив-Си настолько хорош, что сделать это можно достаточно просто, используя другие сообщения вьюхе. (Осознавая, чтó вы делаете.)

Например:

[self.view.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];

Метод `removeFromSuperview` — это обычный метод вьюхи, чтобы самовыпилиться. Метод `makeObjectsPerformSelector` — это метод NSArray, чтобы выполнить селектор всем его элементам.

А на Свифте, например, так:

for subview in view.subviews as [UIView]   {
  subview.removeFromSuperview()
}

И еще, я не уверен, что это хороший способ, но можно замапить выполнение метода каждому элементу в массиве:

view.subviews.map { $0.removeFromSuperview() }

Вот так можно удалить все сабвьюхи.

2014   code   Objective-C   Swift

Swift

В этом году даб-дабе (WWDC 14), как все уже знают, Эпл представила новый язык разработки — Свифт.

Свифт — современный и клевый язык для работы с Какао и Какао-тач (Cocoa, Cocoa Touch). И, так как этот блог был про всякие классные штуки в ОбджСи, то теперь это одновременно и блог про всякие классные штуки в Свифте! :)

Кстати, в одной из сессий на даб-дабе рассказали, что ОбджСи все равно останется важным:

И обратите внимание на колонку «Хорошие блоги» слева. Там сейчас про ОбджСи. Но скоро все поменяется :)

2014   Objective-C   Swift   Xcode

UIViewContentModeScale

typedef NS_ENUM(NSInteger, UIViewContentMode) {
    UIViewContentModeScaleToFill,
    UIViewContentModeScaleAspectFit,
    UIViewContentModeScaleAspectFill,
    ...
}
UIViewContentMode
2014   in English   Objective-C

UITableViewCellStyle

typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
    UITableViewCellStyleDefault,
    UITableViewCellStyleValue1,
    UITableViewCellStyleValue2,
    UITableViewCellStyleSubtitle
};
UITableViewCellStyle
2014   in English   Objective-C

Циклические ссылки

Если в главном потоке нужно использовать блок, который выполняется в другом потоке, а в блоке необходимо обратиться к объекту этого класса (например, self), то может возникнуть циклическая ссылка на self, и он никогда не уничтожится из памяти.

Получится, что self → имеет strong-ссылку на блок. А блок → strong-ссылку на self. И, так как никто из них не потеряет ссылку на себя, они не уничтожатся при деаллоке.

Чтобы этого не произошло, для использование self в блоке, создается слабая ссылка на self и передается в блок:

__weak typeof(self) wself = self;
[[SoundProvider sharedInstance] makeSome:(NSString *)noise
                       completionHandler:^(id spectrum, NSError *error) {
    if (!error) {
        wself.loud = spectrum;
    }
}];

Теперь self не имеет лишнего родителя, и будет уничтожена при обычном деаллоке.

См. также Working with Blocks в документации Какао.

2014   code   Objective-C

Как сравнить длину строки

Вот еще интересный ход в дополнение к предыдущему посту.

По правилам 3 != (BOOL)YES. Но проверку на BOOL через if тройка, разумеется, пройдет. Поэтому, можно не сравнивать так:

if ([string length] == 0) {
    // NO
} else {
    // YES
}

А делать сразу так:

if ([string length]) {
    // YES
}

Это экономит несколько символов и повышает красоту кода :)

2014   code   Objective-C

Нормализация BOOL

Задача: нужно получить BOOL исходя из чего угодно. Например, если 0 — это NO, а если все, что угодно — YES. И по правилам 3 != (BOOL)YES. То есть, нет смысла в выражении [button setEnabled:3];

Поэтому делаем так:

— (BOOL)checkForBool
{
    return !!self.tabBarController;
}

Как это работает? Это двойное отрицание. Возвращает честный YES, если массив не пустой. Внутри компании мы это называем нормализацией.

Да, кстати, всяким классным штукам я учусь у бога обджектив-си @bergusman (фолловьте его :)

2014   code   Objective-C
Ранее Ctrl + ↓