Objective-Cブロックをプロパティとして使用できますか?
-
30-09-2019 - |
質問
標準のプロパティ構文を使用して、プロパティとしてブロックを作成することは可能ですか?
の変更はありますか アーク?
解決
@property (nonatomic, copy) void (^simpleBlock)(void);
@property (nonatomic, copy) BOOL (^blockWithParamter)(NSString *input);
いくつかの場所で同じブロックを繰り返す場合は、タイプDEFを使用します
typedef void(^MyCompletionBlock)(BOOL success, NSError *error);
@property (nonatomic) MyCompletionBlock completion;
他のヒント
このようなタスクをどのように達成するかの例は次のとおりです。
#import <Foundation/Foundation.h>
typedef int (^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];
}
@end
int main () {
@autoreleasepool {
myobj *ob = [[myobj alloc] init];
ob.compare = ^
{
return rand();
};
NSLog(@"%i", ob.compare());
// if not ARC
[ob release];
}
return 0;
}
さて、比較のタイプを変更する必要がある場合に変更する必要がある唯一のものは、 typedef int (^IntBlock)()
. 。 2つのオブジェクトを渡す必要がある場合は、これに変更してください。 typedef int (^IntBlock)(id, id)
, 、およびブロックを変更します。
^ (id obj1, id obj2)
{
return rand();
};
これが役立つことを願っています。
2012年3月12日編集:
ARCの場合、ARCはコピーとして定義されている限り、ブロックを管理するため、特定の変更は必要ありません。デストラクタでプロパティをゼロに設定する必要はありません。
詳細については、このドキュメントをご覧ください。http://clang.llvm.org/docs/automaticreferencecounting.html
Swiftについては、閉鎖を使用するだけです。 例。
Objective-Cで、
@property(copy)void(^dostuff)(void);
そんなに簡単です。
Appleのドキュメント、この問題を完全に説明しています。
.hファイル:
// 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();
}
時代遅れの例コードに注意してください。
Modern(2014+)システムでは、ここに示されていることを行います。そんなに簡単です。それが誰かを助けることを願っています。メリークリスマス2013!
後世 /完全性のために…この途方もなく多才な「物事の方法」を実装する方法の2つの完全な例を以下に示します。 @ロバートの答えは至福の簡潔で正しいですが、ここでは、ブロックを実際に「定義」する方法も示したいと思います。
@interface ReusableClass : NSObject
@property (nonatomic,copy) CALayer*(^layerFromArray)(NSArray*);
@end
@implementation ResusableClass
static NSString const * 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"];
}
return list;
};
}
@end
馬鹿な? はい。 使える? 地獄ええ。 ここに、プロパティを設定する「より原子的」の方法と、途方もなく便利なクラスがあります…
@interface CALayoutDelegator : NSObject
@property (nonatomic,strong) void(^layoutBlock)(CALayer*);
@end
@implementation CALayoutDelegator
- (id) init {
return self = super.init ?
[self setLayoutBlock: ^(CALayer*layer){
for (CALayer* sub in layer.sublayers)
[sub someDefaultLayoutRoutine];
}], self : nil;
}
- (void) layoutSublayersOfLayer:(CALayer*)layer {
self.layoutBlock ? self.layoutBlock(layer) : nil;
}
@end
これは、アクセサを介してブロックプロパティを設定することを示しています(Initの内部ではありますが、議論の余地のない練習です。)vs最初の例の「非原子」「ゲッター」メカニズム。どちらの場合でも…「ハードコーディングされた」実装はいつでも上書きできます。 インスタンスごと..lá..
CALayoutDelegator *littleHelper = CALayoutDelegator.new;
littleHelper.layoutBlock = ^(CALayer*layer){
[layer.sublayers do:^(id sub){ [sub somethingElseEntirely]; }];
};
someLayer.layoutManager = littleHelper;
また..カテゴリにブロックプロパティを追加する場合は...古い学校のターゲット /アクション「アクション」の代わりにブロックを使用するとします...関連する値を使用することができます。ブロックを関連付けます。
typedef void(^NSControlActionBlock)(NSControl*);
@interface NSControl (ActionBlocks)
@property (copy) NSControlActionBlock actionBlock; @end
@implementation NSControl (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
ドラマ..創造で行われる仕事を関連付けるだけです...
_button.actionBlock = ^(NSControl*thisButton){
[doc open]; [thisButton setEnabled:NO];
};
このパターンを適用できます 何度も ココアAPI。プロパティを使用して、コードの関連する部分をもたらす 互いに接近, 、 排除 複雑な委任パラダイム, 、そして、愚かな「容器」として機能するだけのオブジェクトの力を活用します。
もちろん、ブロックをプロパティとして使用できます。しかし、それらがとして宣言されていることを確認してください @Property(コピー). 。例えば:
typedef void(^TestBlock)(void);
@interface SecondViewController : UIViewController
@property (nonatomic, copy) TestBlock block;
@end
MRCでは、コンテキスト変数をキャプチャするブロックがで割り当てられます スタック;スタックフレームが破壊されると、それらは解放されます。それらがコピーされた場合、新しいブロックが割り当てられます ヒープ, 、スタックフレームがポップされた後、後で実行できます。
ディスカマー
これは「良い答え」であることを意図したものではありません。この質問は、Objectivecを明示的に求めています。 AppleがWWDC14でSwiftを導入したとき、Swiftでブロック(または閉鎖)を使用するさまざまな方法を共有したいと思います。
こんにちは、スイフト
Swiftの機能に相当するブロックを渡すために提供される多くの方法があります。
3つを見つけました。
これを理解するには、この小さなコードの遊び場でテストすることをお勧めします。
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は非同期開発のために最適化されているため、Appleは閉鎖にもっと取り組みました。 1つ目は、関数の署名を推測できるため、書き換える必要がないことです。
数字でパラメーションにアクセスします
let resultShortAnon = test({return "ANON_" + $0 + "__ANON" })
命名を伴うパラマシングの推論
let resultShortAnon2 = test({myParam in return "ANON_" + myParam + "__ANON" })
後続の閉鎖
この特別なケースは、ブロックが最後の引数である場合にのみ機能します、それは呼ばれます 後続の閉鎖
これが例です(迅速なパワーを示すために推測された署名と合併)
let resultTrailingClosure = test { return "TRAILCLOS_" + $0 + "__TRAILCLOS" }
ついに:
私がしていることをすべて使用することは、閉鎖の閉鎖とタイプの推論を混合することです(読みやすさのために命名)
PFFacebookUtils.logInWithPermissions(permissions) {
user, error in
if (!user) {
println("Uh oh. The user cancelled the Facebook login.")
} else if (user.isNew) {
println("User signed up and logged in through Facebook!")
} else {
println("User logged in through Facebook!")
}
}
こんにちは、スイフト
@francescuが答えたものを補完します。
追加のパラメーターの追加:
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)
以下の形式に従って、 testingObjectiveCBlock
クラスのプロパティ。
typedef void (^testingObjectiveCBlock)(NSString *errorMsg);
@interface MyClass : NSObject
@property (nonatomic, strong) testingObjectiveCBlock testingObjectiveCBlock;
@end
詳細については、ご覧ください ここ