пятница, 12 июня 2015 г.

Extending protocol on obj-c

Protocol extension? Well, who stops you from doing that in objective-c?
Maybe, not the way you want, but it works with pretty same logic.

Let’s we have 

@protocol Annoyable <NSObject>

- (void)doMagic;

@end


@interface Routine : NSObject <Annoyable>

@end


@interface SwiftFeatureListening : NSObject <Annoyable>

@end


And you want to add new method to the Annoyable protocol -doMagicTwice which calls doMagic two times.

Just do it using old plain c:

.h:
@protocol Annoyable <NSObject>

- (void)doMagic;

void AnnoyableDoMagicTwice(id<Annoyable> obj);

@end

.m:

void AnnoyableDoMagicTwice(id<Annoyable> obj) {
    [obj doMagic];
    [obj doMagic];
}

Surely, swift way is more easy. But it’s not unique language feature.

The most important the way you think. 
You need to add special method, which implementation is relies on declared protocol methods and does not need any information about concrete classes. 

This is an anonymous method with a protocol-conformed object as argument. Let’s declare and implement method - that’s all!

Update: Got it. You can't override this method in classes. But I'm not sure, that overriding methods implemented in protocol extension is good.

понедельник, 28 апреля 2014 г.

UITableView with dynamic cell heights. The root.

The most common problem in building tables in iOS is table with dynamic height cells.
First of all, that’s the ideal scheme looks as follows: table view asks delegate for cell height, and then asks data source for configured (possibly new-created) cell.
According to MVC patter, model contains data to present (so it should not calculate cell’s height), controller should «transfer» model properties to view for representing (so it should not calculate cell height, but can ask cell for it’s actual size) and the cell/view representing some data (without understanding and suggestions about what this data means).
So we should set cell content and ask for actual size and than get size. But we should do it before we have any cell. Looks a little  weird in my opinion.
Let's deal with problems as they arise.
I’d prefer create prototype cell which configured exactly the same way as table view cells. So we should do following things: our datasource/delegate should implement method for initial cell configuring (for new created cell) and data cell configuring (for data representing). When we need to calculate cell height we just use common method to configure cell and configure prototype cell. Then we just call sizeThatFit using size with table view width and zero height. And then we grab prototype cell bounds height.
What’s next? Out prototype cell can hold height for cells to avoid permanent recalculations.
The best part of this method is you can also keep not only height but complex cell components layout! You can create structs with CGRect fields and cell width. You may create NSValue category to keep this structs in any NSDictionary instance (normally using NSIndexPath indexes as keys). So you create structure with fields ‘cell’Width’, ’titleRect’, ‘detailsRet’. And then in first layout keeping calculated values in this structure. Then you keep it in prototype cell. Next time you just check if prototype cell has recalculated layout for given cell width. Pretty simple.
Surely, we have bad sides. First of all, layout caching implementation normally is a good piece of code. For every cell class. But hey, complex cell normally has big implementation.
Also, we have to inherit cells from some «able-to-prototype» cell class. Surely, you can use protocols but it’s just give you more problems. That is the task I working on.

Yep, that issue is common problem and every developer looks for it's own decision. 
So the overall answer is just does not exist. You can also calculate cell heights in view controller (not very well but useful, actually), you can use UICollectionView (in iOS 7 still have nasty bugs) or you can avoid of using UITableView and use power of it's parent - UIScrollView (Yep, in some cases you can just add subviews to UIScrollView. That's reasonable when you have less-repeating cache-meanless data to represent).

More code, less words in future.

пятница, 29 марта 2013 г.

Adobe Photoshop CS 5 + ScriptingBridge


Following text in Russian describes results of generating Photoshop CS 5 header files fro Scripting Bridge.

App | Header File size

iTunes | 25 KB
Xcode | 60 KB
Photoshop CS 5 | 143 Kb (it's really huge!)
Seems like you have a great opportunities using scripting bridge with Photoshop CS 5 on OS X.



В ходе написания маленькой утилиты под собственные нужды  обнаружил, что Photoshop CS 5 обладает интерфейсом под ScriptingBridge (фреймворк от Apple, позволяющий программам "общаться" между собой используя привычные вызовы методов, объявленных в генерируемом заголовочном файле). Причем, заголовочный файл снабжен комментариями и весом под стать самой программе - 143 КБ (127 интерфейсов для различных классов).
Для сравнения - аналогичный файл для iTunes весит 25 КБ, для Xcode - 60 КБ (самый "тяжелый" с которым мне приходилось работать).
Возможности взаимодействия, судя по всему, широкие, вплоть до применения фильтров с настроенными опциями.

понедельник, 21 января 2013 г.

Sometimes "\n" is just "\n"

Usually we use "\n" to make a line break in NSString object. But in -description override "\n" stay "\n".
It's not very good if you want to show an object series or whatever. In this case you may use "\r" to make a line break. 
Some extra info on Stackoverflow.

среда, 9 января 2013 г.

He's died...

Do you know that there is "NSConnectionDidDieNotification" exists?
My boss told me: "Yeah, and if NSNotificationServer have not observers it returns NSNotificationCenterForeverAlone!"

среда, 17 октября 2012 г.

ARC и [[self retain] autorelease]


Иногда нужно быть уверенным, что объект просуществует как минимум до конца собственного вызванного метода. 
До ARC мы обычно писали в таких случаях [[self retain] autorelease]; (выглядит не очень приятно, согласен), но ARC в числе прочих забот принес и необходимость ввести какую-то замену этому способу.
Думаю, когда обычные разработчики оказываются перед подобной проблемой, они обычно спрашивают себя: "А что бы сделали разработчики из Apple?". К счастью, в данном случае разработчики Apple продемонстрировали свой вариант решения проблемы, на который я наткнулся просматривая обновленный код демо-проекта SimplePing.
Дабы не быть голословным приведу просто код. 
Итак, в теле метода, где self должен гарантированно существовать на момент завершения вызова метода:

 [self performSelector:@selector(noop) withObject:nil afterDelay:0.0];

Само же описание метода феноменально:
- (void)noop
{

}

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

четверг, 4 октября 2012 г.

Выстрелить в ногу на Objective-C

Поскольку Objective-C в корне своем - С, то можно просто выстрелить себе в ногу. Но это неинтересно.

Архитектурно задача выглядит следующим образом: объект класса "Пистолет" получает сообщение "сделатьВыстрелВ:" с параметром - объект класса "Нога".

Вспоминаем, что Нога не отвечает протоколу "ОбъектКоторыйМожетБытьЦельюВыстрела". Создаем протокол, прописываем реализацию обязательного метода "получилаВыстрел:".

Запускаем. Работает, но остается патрон на полу. Прибираемся. Вспоминаем времена до ARC, когда за уборкой каждого патрона приходилось следить самому. Ворчим на новое поколение стреляющих, которые не застали эти славные времена, поэтому управление патронами не понимают, в результате чего в случае появления патрона часто не знают, что делать вообще. 

Визуализируем. Для объектов создаем по несколько типов изображений: одно для iPhone, второе для iPhone с Retina-экраном, третье для нового iPhone c вытянутым экраном и еще одно для iPad. 

Следуя концепции MVC пишем контроллер - курок.

Портируем версию на Mac Os X (у всех классов интерфейса заменяем префикс UI на NS) . За время, пока мы пишем - выходит новое видео с WWDC, после просмотра которого оказывается, что в новой операционной системе есть библиотека выстрелов с картинками, методами и отличной документацией, а в разделе для разработчиков на сайте Apple есть проект-пример, в котором демонстрируется как выстрелить не только в ногу и не только себе. Плачем, потому что надо поддерживать iOS предыдущей версии. Видит око, да зуб неймет. Думаем, где взять время, чтобы посмотреть хотя бы половину роликов с новой конференции, когда еще с прошлой штук десять непросмотренных осталось.

Выходит новая операционная система и Xcode. Разработка замедляется - среда разработки явно работает медленнее, более требовательная операционная система подливает масла в огонь. Долгожданной функции вставки заголовков отсутствующих обязательных методов протокола в класс, который объявлен поддерживающим этот протокол все еще нет.

Вспоминаешь, как много написано, решаешь закоммитить проект. Синхронизируешь с github. Во время синхронизации Xcode сбоит и запарывает проект. С мыслями о том, что для лузеров как ты была, есть и будет теплая ламповая консоль, через которую и надо работать с git, берешь настоящий пистолет и тестируешь проект в реальных условиях с поправкой на голову вместо ноги.

@end