Apakah mungkin untuk memiliki blok sebagai properti menggunakan sintaks properti standar?
Apakah ada perubahan untuk ARC ?
Apakah mungkin untuk memiliki blok sebagai properti menggunakan sintaks properti standar?
Apakah ada perubahan untuk ARC ?
Jawaban:
@property (nonatomic, copy) void (^simpleBlock)(void);
@property (nonatomic, copy) BOOL (^blockWithParamter)(NSString *input);
Jika Anda akan mengulangi blok yang sama di beberapa tempat menggunakan tipe def
typedef void(^MyCompletionBlock)(BOOL success, NSError *error);
@property (nonatomic) MyCompletionBlock completion;
@synthesize myProp = _myProp
@synthesize
default adalah apa yang Anda lakukan @synthesize name = _name;
stackoverflow.com/a/12119360/1052616
Berikut adalah contoh bagaimana Anda akan menyelesaikan tugas seperti itu:
#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;
}
Sekarang, satu-satunya hal yang perlu diubah jika Anda perlu mengubah jenis perbandingan adalah typedef int (^IntBlock)()
. Jika Anda perlu mengirimkan dua objek ke sana, ubah ke ini:, typedef int (^IntBlock)(id, id)
dan ubah blok Anda ke:
^ (id obj1, id obj2)
{
return rand();
};
Saya harap ini membantu.
EDIT 12 Maret 2012:
Untuk ARC, tidak ada perubahan khusus yang diperlukan, karena ARC akan mengelola blok untuk Anda selama mereka didefinisikan sebagai salinan. Anda tidak perlu mengatur properti ke nol di destructor Anda, baik.
Untuk bacaan lebih lanjut, silakan periksa dokumen ini: http://clang.llvm.org/docs/AutomaticReferenceCounting.html
Untuk Swift, cukup gunakan penutupan: contoh.
Dalam Objective-C:
@property (copy)void (^doStuff)(void);
Sesederhana itu.
Dalam file .h Anda:
// 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".
Ini file .m Anda:
-(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();
}
Dengan sistem modern (2014+), lakukan apa yang ditunjukkan di sini. Sesederhana itu.
strong
bukan copy
?
nonatomic
seperti praktik terbaik untuk sebagian besar kasus lainnya menggunakan properti?
Demi anak cucu / kelengkapan ... Berikut adalah dua contoh LENGKAP tentang bagaimana menerapkan "cara melakukan sesuatu" yang sangat fleksibel dan serba bisa ini. @ Robert menjawab dengan singkat dan benar, tetapi di sini saya juga ingin menunjukkan cara untuk benar-benar "mendefinisikan" blok.
@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
Bodoh? Iya. Berguna? Hells yeah. Berikut adalah cara pengaturan properti yang lebih "atomik" dan kelas yang sangat berguna ...
@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
Ini menggambarkan pengaturan properti blok melalui accessor (meskipun di dalam init, sebuah praktik yang tidak pasti.) Vs contoh pertama mekanisme "nonatomik" "pengambil". Dalam kedua kasus ... implementasi "hardcoded" selalu dapat ditimpa, misalnya .. a l ..
CALayoutDelegator *littleHelper = CALayoutDelegator.new;
littleHelper.layoutBlock = ^(CALayer*layer){
[layer.sublayers do:^(id sub){ [sub somethingElseEntirely]; }];
};
someLayer.layoutManager = littleHelper;
Juga .. jika Anda ingin menambahkan properti blok dalam suatu kategori ... katakanlah Anda ingin menggunakan Blok alih-alih beberapa "aksi" target / aksi sekolah lama ... Anda bisa menggunakan nilai yang terkait dengannya, well .. kaitkan blok.
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
Sekarang, ketika Anda membuat tombol, Anda tidak perlu mengatur beberapa IBAction
drama .. Asosiasikan saja pekerjaan yang harus dilakukan saat penciptaan ...
_button.actionBlock = ^(NSControl*thisButton){
[doc open]; [thisButton setEnabled:NO];
};
Pola ini dapat diterapkan LEBIH dan LEBIH ke API Kakao. Gunakan properti untuk membawa bagian-bagian yang relevan dari kode Anda lebih dekat bersama-sama , menghilangkan paradigma delegasi berbelit-belit , dan leverage kekuatan benda-benda di luar itu hanya bertindak sebagai "wadah" bodoh.
Tentu saja Anda bisa menggunakan blok sebagai properti. Tetapi pastikan mereka dinyatakan sebagai @ properti (copy) . Sebagai contoh:
typedef void(^TestBlock)(void);
@interface SecondViewController : UIViewController
@property (nonatomic, copy) TestBlock block;
@end
Dalam MRC, blok yang menangkap variabel konteks dialokasikan dalam tumpukan ; mereka akan dirilis ketika bingkai tumpukan dihancurkan. Jika mereka disalin, blok baru akan dialokasikan di heap , yang dapat dieksekusi nanti setelah bingkai tumpukan poped.
Ini tidak dimaksudkan sebagai "jawaban yang baik", karena pertanyaan ini diajukan secara eksplisit untuk ObjectiveC. Ketika Apple memperkenalkan Swift di WWDC14, saya ingin berbagi cara berbeda untuk menggunakan blok (atau penutupan) di Swift.
Anda memiliki banyak cara yang ditawarkan untuk melewati blok yang setara dengan fungsi di Swift.
Saya menemukan tiga.
Untuk memahami ini, saya sarankan Anda untuk menguji di bagian kecil ini kode.
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)
Karena Swift dioptimalkan untuk pengembangan asinkron, Apple bekerja lebih banyak pada penutupan. Yang pertama adalah fungsi signature dapat disimpulkan sehingga Anda tidak perlu menulis ulang.
let resultShortAnon = test({return "ANON_" + $0 + "__ANON" })
let resultShortAnon2 = test({myParam in return "ANON_" + myParam + "__ANON" })
Kasus khusus ini hanya berfungsi jika blok adalah argumen terakhir, itu disebut trailing closure
Berikut ini sebuah contoh (digabung dengan tanda tangan yang disimpulkan untuk menunjukkan kekuatan Swift)
let resultTrailingClosure = test { return "TRAILCLOS_" + $0 + "__TRAILCLOS" }
Akhirnya:
Menggunakan semua kekuatan ini apa yang saya lakukan adalah mencampur trailing closure dan ketik inferensi (dengan penamaan agar mudah dibaca)
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!")
}
}
Halo, Swift
Melengkapi apa yang dijawab @Francescu.
Menambahkan parameter ekstra:
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)
Anda dapat mengikuti format di bawah ini dan dapat menggunakan testingObjectiveCBlock
properti di kelas.
typedef void (^testingObjectiveCBlock)(NSString *errorMsg);
@interface MyClass : NSObject
@property (nonatomic, strong) testingObjectiveCBlock testingObjectiveCBlock;
@end
Untuk info lebih lanjut lihat di sini