int multiplier = 7; int (^myBlock)(int) = ^(int num) { return num * multiplier;}; NSLog(@”%d”, myBlock(4)); // 28
// @implementation NSArray (Blocks) // , - (NSArray*)subarrayWithPredicate:(BOOL(^)(id object, NSUInteger idx, BOOL *stop))predicte { NSMutableArray *resultArray = [NSMutableArray array]; BOOL shouldStop = NO; for (id object in self) { if (predicte(object, [self indexOfObjectIdenticalTo:object], &shouldStop)) { [resultArray addObject:object]; } if (shouldStop) { break; } } return [[resultArray copy] autorelease]; } @end // - NSArray *numbers = @[@(5), @(3), @(8), @(9), @(2)]; NSUInteger divisor = 3; NSArray *divisibleArray = [numbers subarrayWithPredicate:^BOOL(id object, NSUInteger idx, BOOL *stop) { BOOL shouldAdd = NO; // 3 NSAssert([object isKindOfClass:[NSNumber class]], @"object != number"); // , divisor if ([(NSNumber *)object intValue] % divisor == 0) { shouldAdd = YES; } return shouldAdd; }]; NSLog(@"%@", divisibleArray); // 3, 9
typedef int (^MyBlockType)(int number, id object);
int multiplier = 7; auto lambda = [&multiplier](int num) throw() -> int { return multiplier * num; }; lambda(4); // 28
[]
- the beginning of the declaration of lambda, inside - capture context&multiplier
- the captured variable ( &
means it is captured by reference)int
- input parametermutable
- a keyword that allows you to modify variables captured by valuethrow()
- means that lambda does not throw any exceptions out template<class InputCollection, class UnaryPredicate> void subset(InputCollection& inputCollection, InputCollection& outputCollection, UnaryPredicate predicate) { typename InputCollection::iterator iterator = inputCollection.begin(); for (;iterator != inputCollection.end(); ++iterator) { if (predicate(*iterator)) { outputCollection.push_back(*iterator); } } return; } int main(int argc, const char * argv[]) { int divisor = 3; std::vector<int> inputVector = {5, 3, 8, 9, 2}; std::vector<int> outputVector; subset(inputVector, outputVector, [divisor](int number){return number % divisor == 0;}); // std::for_each( outputVector.begin(), outputVector.end(), [](const int& number){std::cout << number << std::endl;} ); }
multiplier
variable (unlike lambda, in lambda we could specify [&]
to capture the entire context by reference, or [=]
to capture the entire context by value).__block
modifier __block int first = 7; void (^myBlock2)(int) = ^(int second) { first += second;}; myBlock2(4); NSLog(@"%d", first); // 11
__block
. After all, in fact, when we send a message to an object, we do not change its pointer. NSMutableArray *array = [NSMutableArray array]; void (^myBlock3)() = ^() { [array addObject:@"someString"];}; myBlock3(); // someString array
__block
to avoid memory leaks. (More on this in the “Memory Management” section)[&]
- means that we capture all the characters by reference.[=]
- all characters by value[a, &b]
- a
captured by value, b
captured by reference[]
- nothing is capturedmutable
specifier, it saysNSGlobalBlock
is created, which is implemented as a singleton.NSStackBlock
is created, which is no longer a singleton but resides on the stack.Block_copy
function, or we want our block to be saved inside some object located in the heap, for example, as a property of the object: @property (nonatomic, copy) MyBlockType myBlock;
then an object of class NSMallocBlock
is created that captures and captures (takes possession of == sends a retain
message) objects passed in context. This is a very important property, because it can lead to memory leaks if you are not careful about it. Blocks can create cycles of ownership (retain cycle). It is also important to note that if we use the value of a property
in NSMallocBlock
, the property itself does not retain, but the object to which the property belongs.HTTP
request with the asynchronous API PKHTTPReuquest
typedef void (^PKHTTPRequestCompletionSuccessBlock)(NSString *responseString); typedef void (^PKHTTPRequestCompletionFailBlock)(NSError* error); @protocol PKRequest <NSObject> - (void)startRequest; @end @interface PKHTTPRequest : NSObject <PKRequest> // designated initializer - (id)initWithURL:(NSURL *)url successBlock:(PKHTTPRequestCompletionSuccessBlock)success failBlock:(PKHTTPRequestCompletionFailBlock)fail; @end
@interface PKHTTPRequest () <NSURLConnectionDelegate> @property (nonatomic, copy) PKHTTPRequestCompletionSuccessBlock succesBlock; @property (nonatomic, copy) PKHTTPRequestCompletionFailBlock failBlock; @property (nonatomic, retain) NSURL *url; @property (nonatomic, retain) NSURLConnection *connection; @property (nonatomic, retain) NSMutableData *data; @end @implementation PKHTTPRequest #pragma mark - initialization / deallocation // designated initializer - (id)initWithURL:(NSURL *)url successBlock:(PKHTTPRequestCompletionSuccessBlock)success failBlock:(PKHTTPRequestCompletionFailBlock)fail { self = [super init]; if (self != nil) { self.succesBlock = success; self.failBlock = fail; self.url = url; NSURLRequest *request = [NSURLRequest requestWithURL:self.url]; self.connection = [[[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO] autorelease]; } return self; } - (id)init { NSAssert(NO, @"Use desiganted initializer"); return nil; } - (void)dealloc { self.succesBlock = nil; self.failBlock = nil; self.url = nil; self.connection = nil; self.data = nil; [super dealloc]; } #pragma mark - public methods - (void)startRequest { self.data = [NSMutableData data]; [self.connection start]; } #pragma mark - NSURLConnectionDelegate implementation - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { [self.data appendData:data]; } - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { self.failBlock(error); self.data = nil; } - (void)connectionDidFinishLoading:(NSURLConnection *)connection { self.succesBlock([NSString stringWithUTF8String:self.data.bytes]); self.data = nil; } @end
PKGetUserNameRequest
that works with PKHTTPReuquest
typedef void (^PKGetUserNameRequestCompletionSuccessBlock)(NSString *userName); typedef void (^PKGetUserNameRequestCompletionFailBlock)(NSError* error); @interface PKGetUserNameRequest : NSObject <PKRequest> - (id)initWithUserID:(NSString *)userID successBlock:(PKGetUserNameRequestCompletionSuccessBlock)success failBlock:(PKGetUserNameRequestCompletionFailBlock)fail; @end
NSString *kApiHost = @"http://someApiHost.com"; NSString *kUserNameApiKey = @"username"; @interface PKGetUserNameRequest () @property (nonatomic, retain) PKHTTPRequest *httpRequest; - (NSString *)parseResponse:(NSString *)response; @end @implementation PKGetUserNameRequest #pragma mark - initialization / deallocation - (id)initWithUserID:(NSString *)userID successBlock:(PKGetUserNameRequestCompletionSuccessBlock)success failBlock:(PKGetUserNameRequestCompletionFailBlock)fail { self = [super init]; if (self != nil) { NSString *requestString = [kApiHost stringByAppendingFormat:@"?%@=%@", kUserNameApiKey, userID]; self.httpRequest = [[[PKHTTPRequest alloc] initWithURL:[NSURL URLWithString:requestString] successBlock:^(NSString *responseString) { // - self NSString *userName = [self parseResponse:responseString]; success(userName); } failBlock:^(NSError *error) { fail(error); } ] autorelease]; } return self; } - (id)init { NSAssert(NO, @"Use desiganted initializer"); return nil; } - (void)dealloc { self.httpRequest = nil; [super dealloc]; } #pragma mark - public methods - (void)startRequest { [self.httpRequest startRequest]; } #pragma mark - private methods - (NSString *)parseResponse:(NSString *)response { /* ...... */ return userName; } @end
NSString *userName = [self parseResponse:responseString];
- when we call something on self in the Malloc block, self retains, the following cycle is formed in the ownership graph: // __block PKGetUserNameRequest *selfRequest = self; self.httpRequest = [[[PKHTTPRequest alloc] initWithURL:[NSURL URLWithString:requestString] successBlock:^(NSString *responseString) { NSString *userName = [selfRequest parseResponse:responseString]; success(userName); } failBlock:^(NSError *error) { fail(error); } ] autorelease];
startRequest
method,startRequestwithCompaltion:fail:
and re-run blocks only for the duration of the request. Then it would be possible to do without the __block
modifier. This would solve another problem: in the example above, there is a danger that by the time the block is called (by the time the request is completed) the PKGetUserNameRequest object will no longer exist (the dealloc method will be called), since the block provides a weak link. And according to the selfRequest
pointer, selfRequest
will hang, which will cause a crash. void addBlockToArray(NSMutableArray* array) { NSString *string = @"example string"; [array addObject:^{ printf("%@\n", string); }]; } void example() { NSMutableArray *array = [NSMutableArray array]; addBlockToArray(array); void (^block)() = [array objectAtIndex:0]; block(); }
// â„–1 auto lamb = []() {return 5;}; auto func_lamb_ptr = new std::function<int()>(lamb); // â„–2: auto lamb = []() {return 5;}; auto* p = new decltype(lamb)(lamb); // â„–3: template <typename T> T* heap_alloc(T const& value) { return new T(value); } auto* p = heap_alloc([]() {return 5;}); // â„–4: std::vector<decltype(lamb)> v; v.push_back(lamb);
auto lambda = [multiplier](int num) throw() mutable
we could change the value of the multiplier
inside the lambda, but the multipler declared in the function would not change. Moreover, the modified multiplier
value is retained from the call to the call of this instance of lambda. You can think of it this way: in the lambda instance (in the object), variable members are created corresponding to the passed parameters. Here you need to be careful, because if we copy a copy of the lambda and call it, then these member variables will not change in the original lambda, they will change only in the copied one. Sometimes you need to pass the lambda wrapped in std::ref
. Obj-C blocks do not provide such an opportunity out of the box. void (^block_example)(int); auto lambda_example = [](int number){number++; NSLog(@"%d", number);}; block_example = lambda_example; block_example(10); // log 11
std::function
can lead to hanging links. int main() { auto lambda1 = []() -> void { printf("Lambda 1!\n"); }; lambda1 = lambda1; // error: use of deleted function 'main()::<lambda()>& main()::<lambda()>::operator=(const main()::<lambda()>&)' return 0; }
Source: https://habr.com/ru/post/204356/
All Articles