Ну, потому что это было бы очень удобно. Мне не нужно знать, что это такое, если у меня правильный синтаксис и он ведет себя как объект NSObject.
Гургет
5
Если вы не знаете, что это такое, как вы узнаете, что это будет очень удобно?
Стивен Кэнон
5
Вы не должны использовать их, если вы не знаете, что они такое :)
Ричард Дж. Росс III,
5
@ Моше вот несколько причин, которые приходят на ум. Блоки легче реализовать, чем полный класс делегата, блоки легкие, и у вас есть доступ к переменным, которые находятся в контексте этого блока. Обратные вызовы событий могут быть эффективно выполнены с использованием блоков (cocos2d использует их почти исключительно).
Ричард Дж. Росс III
2
Не полностью связаны, но так как некоторые комментарии жалуются на «уродливый» блочный синтаксис, вот отличная статья, которая выводит синтаксис из первых принципов: nilsou.com/blog/2013/08/21/objective-c-blocks-syntax
С xCode 4.4 или новее вам не нужно синтезировать. Это сделает его еще более кратким. Apple Doc
Эрик
вау, я этого не знал, спасибо! ... Хотя я часто это делаю@synthesize myProp = _myProp
Роберт
7
@Robert: Вам снова повезло, потому что без установки @synthesizeзначения по умолчанию - это то, что вы делаете @synthesize name = _name;stackoverflow.com/a/12119360/1052616
Эрик
1
@CharlieMonroe - Да, вы, вероятно, правы, но вам не нужна реализация dealloc для обнуления или освобождения свойства блока без ARC? (Прошло много времени с тех пор, как я использовал не-ARC)
Роберт
1
@imcaptor: Да, это может вызвать утечку памяти, если вы не освободите ее в dealloc - как и в любой другой переменной.
Чарли Монро
210
Вот пример того, как вы могли бы выполнить такую задачу:
#import <Foundation/Foundation.h>typedefint(^IntBlock)();@interface myobj :NSObject{IntBlock compare;}@property(readwrite, copy)IntBlock compare;@end@implementation myobj
@synthesize compare;-(void)dealloc
{// need to release the block since the property was declared copy. (for heap// allocated blocks this prevents a potential leak, for compiler-optimized // stack blocks it is a no-op)// Note that for ARC, this is unnecessary, as with all properties, the memory management is handled for you.[compare release];[super dealloc];}@endint main (){@autoreleasepool{
myobj *ob =[[myobj alloc] init];
ob.compare =^{return rand();};NSLog(@"%i", ob.compare());// if not ARC[ob release];}return0;}
Теперь единственное, что нужно изменить, если вам нужно изменить тип сравнения, это typedef int (^IntBlock)(). Если вам нужно передать ему два объекта, измените его на следующее: typedef int (^IntBlock)(id, id)и измените свой блок на:
^(id obj1, id obj2){return rand();};
Надеюсь, это поможет.
РЕДАКТИРОВАТЬ 12 марта 2012 г .:
Для ARC особых изменений не требуется, так как ARC будет управлять блоками за вас, пока они определены как копии. Вам также не нужно устанавливать свойство равным nil в вашем деструкторе.
// Here is a block as a property://// Someone passes you a block. You "hold on to it",// while you do other stuff. Later, you use the block.//// The property 'doStuff' will hold the incoming block.@property(copy)void(^doStuff)(void);// Here's a method in your class.// When someone CALLS this method, they PASS IN a block of code,// which they want to be performed after the method is finished.-(void)doSomethingAndThenDoThis:(void(^)(void))pleaseDoMeLater;// We will hold on to that block of code in "doStuff".
Вот ваш файл .m:
-(void)doSomethingAndThenDoThis:(void(^)(void))pleaseDoMeLater
{// Regarding the incoming block of code, save it for later:
self.doStuff = pleaseDoMeLater;// Now do other processing, which could follow various paths,// involve delays, and so on. Then after everything:[self _alldone];}-(void)_alldone
{NSLog(@"Processing finished, running the completion block.");// Here's how to run the block:if( self.doStuff != nil )
self.doStuff();}
Остерегайтесь устаревшего примера кода.
С современными (2014+) системами делайте то, что показано здесь. Это так просто.
Ради потомства / полноты ... Вот два ПОЛНЫХ примера того, как реализовать этот смехотворно универсальный «способ делать вещи». Ответ Роберта блаженно лаконичен и точен, но здесь я также хочу показать, как на самом деле «определить» блоки.
@interfaceReusableClass:NSObject@property(nonatomic,copy)CALayer*(^layerFromArray)(NSArray*);@end@implementationResusableClassstaticNSStringconst* privateScope =@"Touch my monkey.";-(CALayer*(^)(NSArray*)) layerFromArray {return^CALayer*(NSArray*array){CALayer*returnLayer =CALayer.layer
for(id thing in array){[returnLayer doSomethingCrazy];[returnLayer setValue:privateScope
forKey:@"anticsAndShenanigans"];}returnlist;};}@end
Глупо? Да. Полезно? Ада, да. Вот другой, «более атомарный» способ установки свойства… и класс, который до смешного полезен…
Это иллюстрирует установку свойства блока через аксессор (хотя и внутри init, с сомнительной рискованной практикой ...) по сравнению с «неатомным» механизмом «получения» в первом примере. В любом случае ... «жестко запрограммированные» реализации всегда могут быть перезаписаны, например .. a lá ..
Также ... если вы хотите добавить свойство блока в категорию ... скажем, вы хотите использовать блок вместо какой-то "старой" цели / действия старой школы ... Вы можете просто использовать связанные значения для, ну .. связать блоки.
typedefvoid(^NSControlActionBlock)(NSControl*);@interfaceNSControl(ActionBlocks)@property(copy)NSControlActionBlock actionBlock;@end@implementationNSControl(ActionBlocks)-(NSControlActionBlock) actionBlock {// use the "getter" method's selector to store/retrieve the block!return objc_getAssociatedObject(self, _cmd);}-(void) setActionBlock:(NSControlActionBlock)ab {
objc_setAssociatedObject(// save (copy) the block associatively, as categories can't synthesize Ivars.
self,@selector(actionBlock),ab ,OBJC_ASSOCIATION_COPY);
self.target = self;// set self as target (where you call the block)
self.action =@selector(doItYourself);// this is where it's called.}-(void) doItYourself {if(self.actionBlock && self.target == self) self.actionBlock(self);}@end
Теперь, когда вы делаете кнопку, вам не нужно настраивать какую-то IBActionдраму ... Просто свяжите работу, которая будет сделана при создании ...
Этот шаблон может применяться OVER и OVER к API какао. Используйте свойство , чтобы принести соответствующие части коды ближе друг к другу , устранить запутанные парадигмы делегирования и рычаги власти объектов за что просто действуют как немые «контейнеры».
Алекс, отличный пример. Вы знаете, мне интересно о неатомическом. Мысли?
Толстяк
2
Это очень редко, что "атомное" будет правильным решением для собственности. Было бы очень странно , что нужно установить свойство блока в одном потоке и читать его в другом потоке в то же время , или установить свойство блока одновременно из нескольких потоков. Таким образом, цена «атомарного» против «неатомного» не дает вам никаких реальных преимуществ.
gnasher729
8
Конечно, вы можете использовать блоки в качестве свойств. Но убедитесь, что они объявлены как @property (copy) . Например:
В MRC блоки захвата переменных контекста размещаются в стеке ; они будут освобождены при разрушении кадра стека. Если они скопированы, новый блок будет размещен в куче , которая может быть выполнена позже после того, как кадр стека будет выдвинут.
Это не предназначено, чтобы быть "хорошим ответом", поскольку этот вопрос задают явно для ObjectiveC. Поскольку Apple представила Swift на WWDC14, я хотел бы поделиться различными способами использования блоков (или замыканий) в Swift.
Привет, Свифт
У вас есть множество способов передать блок, эквивалентный функции в Swift.
Я нашел три.
Чтобы понять это, я предлагаю вам протестировать на игровой площадке этот маленький кусочек кода.
func test(function:String->String)->String{return function("test")}
func funcStyle(s:String)->String{return"FUNC__"+ s +"__FUNC"}
let resultFunc = test(funcStyle)
let blockStyle:(String)->String={s in return"BLOCK__"+ s +"__BLOCK"}
let resultBlock = test(blockStyle)
let resultAnon = test({(s:String)->String in return"ANON_"+ s +"__ANON"})
println(resultFunc)
println(resultBlock)
println(resultAnon)
Swift, оптимизированный для закрытия
Поскольку Swift оптимизирован для асинхронной разработки, Apple больше работала над замыканиями. Во-первых, сигнатура функции может быть выведена, поэтому вам не нужно ее переписывать.
Доступ к параметрам по номерам
let resultShortAnon = test({return"ANON_"+ $0 +"__ANON"})
Вывод параметров с именами
let resultShortAnon2 = test({myParam in return"ANON_"+ myParam +"__ANON"})
Трейлинг-закрытие
Этот особый случай работает, только если блок является последним аргументом, он называется завершающим закрытием
Вот пример (объединен с предполагаемой подписью, чтобы показать силу Swift)
let resultTrailingClosure = test {return"TRAILCLOS_"+ $0 +"__TRAILCLOS"}
В заключение:
Используя всю эту мощь, я бы смешал конечное замыкание и вывод типа (с именами для удобства чтения).
PFFacebookUtils.logInWithPermissions(permissions){
user, error in
if(!user){
println("Uh oh. The user cancelled the Facebook login.")}elseif(user.isNew){
println("User signed up and logged in through Facebook!")}else{
println("User logged in through Facebook!")}}
func test(function:String->String, param1:String, param2:String)->String{return function("test"+param1 + param2)}
func funcStyle(s:String)->String{return"FUNC__"+ s +"__FUNC"}
let resultFunc = test(funcStyle,"parameter 1","parameter 2")
let blockStyle:(String)->String={s in return"BLOCK__"+ s +"__BLOCK"}
let resultBlock = test(blockStyle,"parameter 1","parameter 2")
let resultAnon = test({(s:String)->String in return"ANON_"+ s +"__ANON"},"parameter 1","parameter 2")
println(resultFunc)
println(resultBlock)
println(resultAnon)
Ответы:
Если вы собираетесь повторять один и тот же блок в нескольких местах, используйте тип def
источник
@synthesize myProp = _myProp
@synthesize
значения по умолчанию - это то, что вы делаете@synthesize name = _name;
stackoverflow.com/a/12119360/1052616Вот пример того, как вы могли бы выполнить такую задачу:
Теперь единственное, что нужно изменить, если вам нужно изменить тип сравнения, это
typedef int (^IntBlock)()
. Если вам нужно передать ему два объекта, измените его на следующее:typedef int (^IntBlock)(id, id)
и измените свой блок на:Надеюсь, это поможет.
РЕДАКТИРОВАТЬ 12 марта 2012 г .:
Для ARC особых изменений не требуется, так как ARC будет управлять блоками за вас, пока они определены как копии. Вам также не нужно устанавливать свойство равным nil в вашем деструкторе.
Для получения дополнительной информации, пожалуйста, ознакомьтесь с этим документом: http://clang.llvm.org/docs/AutomaticReferenceCounting.html
источник
Для Swift просто используйте замыкания: пример.
В Objective-C:
@property (copy) void
Это так просто.
Вот актуальная документация Apple, в которой точно указано, что использовать:
Apple Doco.
В вашем .h файле:
Вот ваш файл .m:
Остерегайтесь устаревшего примера кода.
С современными (2014+) системами делайте то, что показано здесь. Это так просто.
источник
strong
вместоcopy
?nonatomic
от лучших практик для большинства других случаев использования свойств?Ради потомства / полноты ... Вот два ПОЛНЫХ примера того, как реализовать этот смехотворно универсальный «способ делать вещи». Ответ Роберта блаженно лаконичен и точен, но здесь я также хочу показать, как на самом деле «определить» блоки.
Глупо? Да. Полезно? Ада, да. Вот другой, «более атомарный» способ установки свойства… и класс, который до смешного полезен…
Это иллюстрирует установку свойства блока через аксессор (хотя и внутри init, с сомнительной рискованной практикой ...) по сравнению с «неатомным» механизмом «получения» в первом примере. В любом случае ... «жестко запрограммированные» реализации всегда могут быть перезаписаны, например .. a lá ..
Также ... если вы хотите добавить свойство блока в категорию ... скажем, вы хотите использовать блок вместо какой-то "старой" цели / действия старой школы ... Вы можете просто использовать связанные значения для, ну .. связать блоки.
Теперь, когда вы делаете кнопку, вам не нужно настраивать какую-то
IBAction
драму ... Просто свяжите работу, которая будет сделана при создании ...Этот шаблон может применяться OVER и OVER к API какао. Используйте свойство , чтобы принести соответствующие части коды ближе друг к другу , устранить запутанные парадигмы делегирования и рычаги власти объектов за что просто действуют как немые «контейнеры».
источник
Конечно, вы можете использовать блоки в качестве свойств. Но убедитесь, что они объявлены как @property (copy) . Например:
В MRC блоки захвата переменных контекста размещаются в стеке ; они будут освобождены при разрушении кадра стека. Если они скопированы, новый блок будет размещен в куче , которая может быть выполнена позже после того, как кадр стека будет выдвинут.
источник
Юридическая информация
Это не предназначено, чтобы быть "хорошим ответом", поскольку этот вопрос задают явно для ObjectiveC. Поскольку Apple представила Swift на WWDC14, я хотел бы поделиться различными способами использования блоков (или замыканий) в Swift.
Привет, Свифт
У вас есть множество способов передать блок, эквивалентный функции в Swift.
Я нашел три.
Чтобы понять это, я предлагаю вам протестировать на игровой площадке этот маленький кусочек кода.
Swift, оптимизированный для закрытия
Поскольку Swift оптимизирован для асинхронной разработки, Apple больше работала над замыканиями. Во-первых, сигнатура функции может быть выведена, поэтому вам не нужно ее переписывать.
Доступ к параметрам по номерам
Вывод параметров с именами
Трейлинг-закрытие
Этот особый случай работает, только если блок является последним аргументом, он называется завершающим закрытием
Вот пример (объединен с предполагаемой подписью, чтобы показать силу Swift)
В заключение:
Используя всю эту мощь, я бы смешал конечное замыкание и вывод типа (с именами для удобства чтения).
источник
Привет, Свифт
В дополнение к тому, что ответил @Francescu.
Добавление дополнительных параметров:
источник
Вы можете следовать формату ниже и можете использовать
testingObjectiveCBlock
свойство в классе.Для получения дополнительной информации посмотрите здесь
источник