Комментарии 7
Сам имею аналогичное решение, похожее на анонимные классы в джаве:
И только для того, чтобы избавиться от id _s, вы решили прибегнуть к такому огромному количеству приседаний и использованию NSInvocation? Why?
tableView.datasource = [ASPDelegate delegate:^(ASPDynamicDelegate* delegate){
[delegate addSelector:@selector(tableView:numberOfRowsInSection:) withBlock:^NSUInteger(id _s, NSTableView *tv, NSUInteger section){
return 10;
}]
}];
И только для того, чтобы избавиться от id _s, вы решили прибегнуть к такому огромному количеству приседаний и использованию NSInvocation? Why?
0
Потому что намного приятнее работать только с тем, что нужно
А поскольку:
и это действительно было увлекательное занятие и я думаю все объясняет ;-)
К тому же адаптация кол-ва аргументов тоже весьма приятно
А поскольку:
Это был всего лишь эксперимент, у меня не было желания написать этот код для использования в проектах.
и это действительно было увлекательное занятие и я думаю все объясняет ;-)
К тому же адаптация кол-ва аргументов тоже весьма приятно
0
Принято :) Не заметил.
Кстати, у Вас в структуре block ABI ошибка, на самом деле она выглядит вот так
Документация is out of date, информацию о реальной имплементации можно найти в исходниках llvm. Разница не принципиальная, и так и так работает, но просто на заметку.
Попробуйте фана ради решить такую задачу: сделать возможным замену методов у конкретного инстанса класса с вызовом оригинальной имплементации перед\до. Например
Блок должен быть вызван в этом примере после отработки оригинальной имплементации и при этом с теми же аргументами. Решение готовое уже есть на гитхабе, можете поискать, но оно использует NSInvocation и, по сему, невероятно медленное (о чем говорит их дока и мой опыт). Однако инструмент очень полезен: можно, например, очень быстро распихать аналитику по всему приложению, не вставляя злосчастные вызовы логинга эвентов посреди бизнес логики или UI.
Нужно сделать без использования NSInvocation. Эта задача мне кажется интересней и сложнее. Все здорово, покуда можно использовать NSInvocation. А вот без него? :) (PS: как видно в примере, _s не убирается и не требуется: у Вас узкий кейс с лямбдами, а эта задача о другом и self часто нужен)
Кстати, у Вас в структуре block ABI ошибка, на самом деле она выглядит вот так
struct ASPBlockDescriptor
{
__unused unsigned long int reserved;
__unused unsigned long int size;
union
{
struct
{
__unused void (*copy_helper)(void *dst, void *src);
__unused void (*dispose_helper)(void *src);
const char *copy_dispose_signature;
};
const char *usual_signature;
};
};
Документация is out of date, информацию о реальной имплементации можно найти в исходниках llvm. Разница не принципиальная, и так и так работает, но просто на заметку.
Попробуйте фана ради решить такую задачу: сделать возможным замену методов у конкретного инстанса класса с вызовом оригинальной имплементации перед\до. Например
[object injectAfter:@selector(someMethod:) withBlock:^(id _s, ArgType arg){}];
Блок должен быть вызван в этом примере после отработки оригинальной имплементации и при этом с теми же аргументами. Решение готовое уже есть на гитхабе, можете поискать, но оно использует NSInvocation и, по сему, невероятно медленное (о чем говорит их дока и мой опыт). Однако инструмент очень полезен: можно, например, очень быстро распихать аналитику по всему приложению, не вставляя злосчастные вызовы логинга эвентов посреди бизнес логики или UI.
Нужно сделать без использования NSInvocation. Эта задача мне кажется интересней и сложнее. Все здорово, покуда можно использовать NSInvocation. А вот без него? :) (PS: как видно в примере, _s не убирается и не требуется: у Вас узкий кейс с лямбдами, а эта задача о другом и self часто нужен)
0
Если честно я был в шоке. Мало того что очень странным путем пошли. Так еще и магию много раз вспомнили.
А как Вам решение в 2 строки?
Главное держать блок столько же, сколько живет кнопка. Можно просто у владельца кнопки создать массив всех блоков. Можно даже к кнопке его приделать — это не хитрый метод, раз вы знакомы с рантайном, добавить проперти в системный класс — плёвое дело.
И вся статья сводится к:
1) Болк это NSObject, Наверно у него есть методы, вот давайте их и используем.
2) А если есть какие то контекстные переменные для блока, то создаем переменную, помечаем ее как __block и используем в блоке как хотим.
Я конечно тоже люблю пилить велосипед для изучения, и более глубоко понимания. Но показывая такое людям, можно дать неверное представление о природе вещей и в будущем вместо поисков короткого пути — пойдут знакомым, долгим и муторным.
Я сам не очень хороший писатель, даже отвратительный, я бы сказал. Но втыкать в центр статьи стороннюю инфу и так увеличивать статью — не хорошо.
P.S Не смотря на комент "When you call this method, target is not retained." у UIControl, даже если не держать ссылку на блок, все работает. Но я всегда храню ссылку на блок. Но раз живет на тестах. то давайте решение будет вообще однострочным.
P.P.S. Я не злой, но за 2 недели вижу такое решение 2ой раз. И считаю что такое на надо рассказывать. Сделали, заработало. Проктической пользы не несёт? Значит прячем в архивы на долгую память.
А как Вам решение в 2 строки?
_buttonOwner.strongPropertyForBlock = block
[button addTarget:block action:@selector(invoke) forControlEvents:UIControlEventTouchUpInside]
Главное держать блок столько же, сколько живет кнопка. Можно просто у владельца кнопки создать массив всех блоков. Можно даже к кнопке его приделать — это не хитрый метод, раз вы знакомы с рантайном, добавить проперти в системный класс — плёвое дело.
И вся статья сводится к:
1) Болк это NSObject, Наверно у него есть методы, вот давайте их и используем.
2) А если есть какие то контекстные переменные для блока, то создаем переменную, помечаем ее как __block и используем в блоке как хотим.
Я конечно тоже люблю пилить велосипед для изучения, и более глубоко понимания. Но показывая такое людям, можно дать неверное представление о природе вещей и в будущем вместо поисков короткого пути — пойдут знакомым, долгим и муторным.
Я сам не очень хороший писатель, даже отвратительный, я бы сказал. Но втыкать в центр статьи стороннюю инфу и так увеличивать статью — не хорошо.
P.S Не смотря на комент "When you call this method, target is not retained." у UIControl, даже если не держать ссылку на блок, все работает. Но я всегда храню ссылку на блок. Но раз живет на тестах. то давайте решение будет вообще однострочным.
P.P.S. Я не злой, но за 2 недели вижу такое решение 2ой раз. И считаю что такое на надо рассказывать. Сделали, заработало. Проктической пользы не несёт? Значит прячем в архивы на долгую память.
Вот вам распечатка интерфейса блока
@interface NSBlock: NSObject {
}
end
}
- (id)copy;
- (id)copyWithZone:(struct _NSZone { }*)arg1;
- (void)invoke;
- (void)performAfterDelay:(double)arg1;
end
0
приведите пример использования invoke, когда блок принимает аргументы
к примеру для вызова через performSelector:withObject:
ну или когда по нажатию на кнопку надо получить кнопку и евент
так же интересно, какое неверное представление я дал о блоках?
p.s. а я и не думал обижаться :-) это про "не злой"
к примеру для вызова через performSelector:withObject:
ну или когда по нажатию на кнопку надо получить кнопку и евент
так же интересно, какое неверное представление я дал о блоках?
p.s. а я и не думал обижаться :-) это про "не злой"
0
"Неверно представление о блоках"
1) target-action на блоках, простенькая задача, но вы написали статью на пару А4, что создает впечатление о неподъемности вопроса
2) Если вы написали там много, и хотели показать всю взаимосвязь, то надо было еще добавить Такую цепочку логики — блок — это объект, объест это структура, простая Сишная структура с определенными правилами формирования. И тогда понятно зачем в статье декларируются странные структуры.
3) Слово магия недопустима в статьях, вообще. Как и мое многократное повторение слово структура :)
Параметры:
1) target-action ни есть задача о performSelector:withObject:
2) Если надо передать объект в блок как в performSelector:withObject:, просто используйте переменную блоке, и все счастливы будут
3) У меня на каждую пару эвент/кнопка всегда свой метод, и поэтому с моей "колокольни" это и не нужно. Но вот если прям очень-очень нужно, то
Да, тут нельзя удалить эвент, но тем не менее, допилить небольшая работа.
Да, ломается 2х строчное решение
Но это все равно меньше пары классов и статьи на пару А4. А по сути всего один метод у UIButton
Если бы Вы ограничили статью только темой "Разбираемся с NSMethodSignature на примере комбинирования stringWithFormat и NSArray" и убрали привязку к target-action — я бы лайкал статью неистово, всем одним лайком который у меня есть.
1) target-action на блоках, простенькая задача, но вы написали статью на пару А4, что создает впечатление о неподъемности вопроса
2) Если вы написали там много, и хотели показать всю взаимосвязь, то надо было еще добавить Такую цепочку логики — блок — это объект, объест это структура, простая Сишная структура с определенными правилами формирования. И тогда понятно зачем в статье декларируются странные структуры.
3) Слово магия недопустима в статьях, вообще. Как и мое многократное повторение слово структура :)
Параметры:
1) target-action ни есть задача о performSelector:withObject:
2) Если надо передать объект в блок как в performSelector:withObject:, просто используйте переменную блоке, и все счастливы будут
3) У меня на каждую пару эвент/кнопка всегда свой метод, и поэтому с моей "колокольни" это и не нужно. Но вот если прям очень-очень нужно, то
typedef void (^ButtonExecutionBlock)(void);
@implementation UIButton (XYZ_SomeLabel)
- (void)XYZ_addBlock:(void (^)(id, UIControlEvents))block forEvent:(UIControlEvents)event
{
weakify(self)
ButtonExecutionBlock eventBlock = ^(void){
strongify(self)
block(self, event);
};
NSString *key = [NSString stringWithFormat:@"%lu", (unsigned long)event];
const char *cKey = [key cStringUsingEncoding:NSUTF8StringEncoding];
NSMutableArray *blocks = objc_getAssociatedObject(self, cKey);
if (blocks == nil) {
blocks = [NSMutableArray array];
objc_setAssociatedObject(self, cKey, blocks, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
[blocks addObject:eventBlock];
[self addTarget:eventBlock
action:@selector(invoke)
forControlEvents:UIControlEventTouchUpInside];
}
@end
Да, тут нельзя удалить эвент, но тем не менее, допилить небольшая работа.
Да, ломается 2х строчное решение
Но это все равно меньше пары классов и статьи на пару А4. А по сути всего один метод у UIButton
Если бы Вы ограничили статью только темой "Разбираемся с NSMethodSignature на примере комбинирования stringWithFormat и NSArray" и убрали привязку к target-action — я бы лайкал статью неистово, всем одним лайком который у меня есть.
0
Если бы Вы ограничили статью только темой «Разбираемся с NSMethodSignature на примере комбинирования stringWithFormat и NSArray» и убрали привязку к target-action
Не поверите, было такое желание вынести центр статьи в отдельную статью с таким названием (и было так в начале кстати). Но потом люди которые читали черновой вариант изъявили желание читать все вместе чтобы не теряться в материале
Да, ломается 2х строчное решение
Но это все равно меньше пары классов и статьи на пару А4. А по сути всего один метод у UIButton
Это и есть тот самый обычный подход о котором я писал что в других либах, только там это делается сразу на уровень выше для остальных контролов чтобы было
И потом такие же для инициализаторов на барбатоны, на таймеры, на жесты и еще на много чего и на самом деле если это собрать, то получится не мало категорий
Здесь решение максимально общее и по факту совсем не большое если сравнивать от эффекта добавления множества категорий
1) target-action ни есть задача о performSelector:withObject:
Вы правы. Но суммарный результат, что решение применимо для любого действия где дергается через селектор вызов, я не смог подобрать лучшее определение
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
До чего доводит идея (Objective-C) — target-action на блоках и много рантайма