A'yı Block
a Function
/ 'ya nasıl aktarabilirim Method
?
Ben - (void)someFunc:(__Block)someBlock
boşuna denedim .
yani. Ne tür bir için Block
?
A'yı Block
a Function
/ 'ya nasıl aktarabilirim Method
?
Ben - (void)someFunc:(__Block)someBlock
boşuna denedim .
yani. Ne tür bir için Block
?
Yanıtlar:
Bir bloğun türü, bağımsız değişkenlerine ve dönüş türüne bağlı olarak değişir. Genel durumda, blok tipleri, işlev işaretçisi türleriyle aynı şekilde bildirilir, ancak yerine *
a kullanılır ^
. Bir bloğu bir yönteme geçirmenin bir yolu şöyledir:
- (void)iterateWidgets:(void (^)(id, int))iteratorBlock;
Ama gördüğünüz gibi, bu dağınık. Bunun yerine typedef
, blok türlerini daha temiz hale getirmek için a kullanabilirsiniz :
typedef void (^ IteratorBlock)(id, int);
Ve sonra bu bloğu şöyle bir yönteme geçirin:
- (void)iterateWidgets:(IteratorBlock)iteratorBlock;
NSNumber *
ya std::string&
veya başka bir şey, bir fonksiyon argüman olarak geçebileceği. Bu sadece bir örnek. (Değiştirilmesi hariç eşdeğer bir blok için id
birlikte NSNumber
, typedef
olurdu typedef void (^ IteratorWithNumberBlock)(NSNumber *, int);
.)
NS_NOESCAPE
, ama enumerateObjectsUsingBlock
söylendi kaçan değil, ama ben NS_NOESCAPE
sitede hiçbir yerde görmüyorum , ne de Apple belgelerinde hiç belirtilen kaçan. Yardım edebilir misin?
Bu soru için en kolay açıklama şu şablonları takip etmektir:
1. Yöntem parametresi olarak engelle
şablon
- (void)aMethodWithBlock:(returnType (^)(parameters))blockName {
// your code
}
Misal
-(void) saveWithCompletionBlock: (void (^)(NSArray *elements, NSError *error))completionBlock{
// your code
}
Vakaların diğer kullanımı:
2. Mülk Olarak Engelle
şablon
@property (nonatomic, copy) returnType (^blockName)(parameters);
Misal
@property (nonatomic,copy)void (^completionBlock)(NSArray *array, NSError *error);
3. Yöntem bağımsız değişkeni olarak engelleyin
şablon
[anObject aMethodWithBlock: ^returnType (parameters) {
// your code
}];
Misal
[self saveWithCompletionBlock:^(NSArray *array, NSError *error) {
// your code
}];
4. Yerel değişken olarak engelle
şablon
returnType (^blockName)(parameters) = ^returnType(parameters) {
// your code
};
Misal
void (^completionBlock) (NSArray *array, NSError *error) = ^void(NSArray *array, NSError *error){
// your code
};
5. typedef olarak engelleyin
şablon
typedef returnType (^typeName)(parameters);
typeName blockName = ^(parameters) {
// your code
}
Misal
typedef void(^completionBlock)(NSArray *array, NSError *error);
completionBlock didComplete = ^(NSArray *array, NSError *error){
// your code
};
Bunu, bloğu bir blok parametresi olarak geçirerek yapabilirsiniz:
//creating a block named "completion" that will take no arguments and will return void
void(^completion)() = ^() {
NSLog(@"bbb");
};
//creating a block namd "block" that will take a block as argument and will return void
void(^block)(void(^completion)()) = ^(void(^completion)()) {
NSLog(@"aaa");
completion();
};
//invoking block "block" with block "completion" as argument
block(completion);
Aşağıdaki örnekte с işlevlerini kullanarak blok geçirmenin başka bir yolu. Arka planda ve ana kuyrukta herhangi bir şey gerçekleştirmek için işlevler oluşturdum.
blocks.h dosyası
void performInBackground(void(^block)(void));
void performOnMainQueue(void(^block)(void));
blocks.m dosyası
#import "blocks.h"
void performInBackground(void(^block)(void)) {
if (nil == block) {
return;
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), block);
}
void performOnMainQueue(void(^block)(void)) {
if (nil == block) {
return;
}
dispatch_async(dispatch_get_main_queue(), block);
}
Gerektiğinde blokları içe aktarın. H ve çağırın:
- (void)loadInBackground {
performInBackground(^{
NSLog(@"Loading something in background");
//loading code
performOnMainQueue(^{
//completion hadler code on main queue
});
});
}
Bloğu sizin için geçerliyse basit bir özellik olarak da ayarlayabilirsiniz:
@property (nonatomic, copy) void (^didFinishEditingHandler)(float rating, NSString *reviewString);
block özelliğinin "kopya" olduğundan emin olun!
ve elbette typedef'i de kullanabilirsiniz:
typedef void (^SimpleBlock)(id);
@property (nonatomic, copy) SimpleBlock someActionHandler;
Ayrıca, normal c işlevi sözdizimini kullanarak bir bloğu çağırır veya çağırırsınız
-(void)iterateWidgets:(IteratorBlock)iteratorBlock{
iteratorBlock(someId, someInt);
}
Buradaki bloklar hakkında daha fazla bilgi
Her zaman blok sözdizimini unutmaya eğilimliyim. Bir blok ilan etmem gerektiğinde aklıma hep geliyor. Umarım birine yardımcı olur :)
Ben çalkalandıktan sonra zar değerlerini döndürecek bir sınıf için bir completionBlock yazdım:
Typedef'i returnType (tanımlamanın .h
üstünde @interface
) ile tanımlayın
typedef void (^CompleteDiceRolling)(NSInteger diceValue);
A @property
( .h
) bloğu için tanımla
@property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
finishBlock
( .h
) İle bir yöntem tanımlama
- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
Önceki tanımlanan yönteme takın .m
dosya ve taahhüt finishBlock
etmek @property
önce tanımlanmış
- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
self.completeDiceRolling = finishBlock;
}
Tetiklemek için completionBlock
önceden tanımlanmış bir değişkenTipi yazın (Var olup olmadığını kontrol etmeyi unutmayın completionBlock
)
if( self.completeDiceRolling ){
self.completeDiceRolling(self.dieValue);
}
Bu iş parçacığında verilen cevaplara rağmen, gerçekten bir Blok fonksiyon olarak - ve bir parametre ile alacak bir fonksiyon yazmak için mücadele etti. Sonunda, burada bulduğum çözüm.
loadJSONthread
Bir JSON Web Hizmeti URL'si alır, bir arka plan iş parçacığında bu URL'den bazı JSON verileri yüklemek, sonra arama işlevine sonuçların bir NSArray * döndürmek genel bir işlev yazmak istedim .
Temel olarak, tüm arka plan iş parçacığı karmaşıklığını yeniden kullanılabilir genel bir işlevde gizli tutmak istedim.
İşte ben bu işlevi şöyle diyorum:
NSString* WebServiceURL = @"http://www.inorthwind.com/Service1.svc/getAllCustomers";
[JSONHelper loadJSONthread:WebServiceURL onLoadedData:^(NSArray *results) {
// Finished loading the JSON data
NSLog(@"Loaded %lu rows.", (unsigned long)results.count);
// Iterate through our array of Company records, and create/update the records in our SQLite database
for (NSDictionary *oneCompany in results)
{
// Do something with this Company record (eg store it in our SQLite database)
}
} ];
... ve bununla uğraştığım bit: nasıl bildirilir ve veri yüklendikten sonra Blok işlevini çağırmak ve yüklü Block
bir NSArray * iletmek için nasıl alınır :
+(void)loadJSONthread:(NSString*)urlString onLoadedData:(void (^)(NSArray*))onLoadedData
{
__block NSArray* results = nil;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
// Call an external function to load the JSON data
NSDictionary * dictionary = [JSONHelper loadJSONDataFromURL:urlString];
results = [dictionary objectForKey:@"Results"];
dispatch_async(dispatch_get_main_queue(), ^{
// This code gets run on the main thread when the JSON has loaded
onLoadedData(results);
});
});
}
Bu StackOverflow soru, bir blok parametre olarak geçen fonksiyonları aramak için, bu yüzden yukarıdaki kodu basitleştirilmiş ve loadJSONDataFromURL
işlevi dahil değil .
Ancak, ilgileniyorsanız, bu JSON yükleme işlevinin bir kopyasını bu blogda bulabilirsiniz: http://mikesknowledgebase.azurewebsites.net/pages/Services/WebServices-Page6.htm
Umarım bu diğer bazı XCode geliştiricilerine yardımcı olur! (Bu soruyu ve cevabımı oylamayı unutmayın, eğer varsa!)
Tam şablon şöyle görünür
- (void) main {
//Call
[self someMethodWithSuccessBlock:^{[self successMethod];}
withFailureBlock:^(NSError * error) {[self failureMethod:error];}];
}
//Definition
- (void) someMethodWithSuccessBlock:(void (^) (void))successBlock
withFailureBlock:(void (^) (NSError*))failureBlock {
//Execute a block
successBlock();
// failureBlock([[NSError alloc]init]);
}
- (void) successMethod {
}
- (void) failureMethod:(NSError*) error {
}