How to Access a _Block Variable, After the Block Has Completed

How do I create my own completion handler as part of method parameters

You need to treat the completion block just like a variable. The method will accept a block as part of it's parameters, then store it for later.

- (void)myMethodWithCompletionHandler:(void (^)(id, NSError*))handler;

You can typedef that block type for easier reading:

typedef void (^CompletionBlock)(id, NSError*);

And then store your block as an instance variable:

In your @interface: CompletionBlock _block;

In the myMethod.. _block = [handler copy]

Then when you want the completion block to execute you just call it like a regular block:

_block(myData, error);

Blocks and Variables

1) Yes you'd need to declare:

__block NSDictionary *results = nil;

If you're using ARC it should automatically take care of retaining and releasing the results object. If not using ARC, then do a retain as the first thing you do and a release as the last thing you do in the block.

2) A block should have visibility of all variables/objects available to it's parent's scope. So in a method you should be able to see all local variables to that method and the object which that method belongs to (as self).

3) Not too sure about this one. Variables do go away once you leave the function/method (which will be as so as most blocks have been called, rather than finished executing), where as anything that is part of self won't. Maybe that has something to do with it.

What does the __block keyword mean?

It tells the compiler that any variable marked by it must be treated in a special way when it is used inside a block. Normally, variables and their contents that are also used in blocks are copied, thus any modification done to these variables don't show outside the block. When they are marked with __block, the modifications done inside the block are also visible outside of it.

For an example and more info, see The __block Storage Type in Apple's Blocks Programming Topics.

The important example is this one:

extern NSInteger CounterGlobal;
static NSInteger CounterStatic;

{
NSInteger localCounter = 42;
__block char localCharacter;

void (^aBlock)(void) = ^(void) {
++CounterGlobal;
++CounterStatic;
CounterGlobal = localCounter; // localCounter fixed at block creation
localCharacter = 'a'; // sets localCharacter in enclosing scope
};

++localCounter; // unseen by the block
localCharacter = 'b';

aBlock(); // execute the block
// localCharacter now 'a'
}

In this example, both localCounter and localCharacter are modified before the block is called. However, inside the block, only the modification to localCharacter would be visible, thanks to the __block keyword. Conversely, the block can modify localCharacter and this modification is visible outside of the block.

Unable to access global variables in dispatch_async : Variable is not Assignable (missing _block type specifier)

You must use the __block specifier when you modify a variable inside a block, so the code you gave should look like this instead:

 __block NSString *textString;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
(unsigned long)NULL), ^(void) {
textString = [self getTextString];
});

Blocks capture the state of the variables referenced inside their bodies, so the captured variable must be declared mutable. And mutability is exactly what you need considering that you're essentially setting this thing.

Retain cycle on `self` with blocks

Strictly speaking, the fact that it's a const copy has nothing to do with this problem. Blocks will retain any obj-c values that are captured when they are created. It just so happens that the workaround for the const-copy issue is identical to the workaround for the retain issue; namely, using the __block storage class for the variable.

In any case, to answer your question, there's no real alternative here. If you're designing your own block-based API, and it makes sense to do so, you could have the block get passed the value of self in as an argument. Unfortunately, this doesn't make sense for most APIs.

Please note that referencing an ivar has the exact same issue. If you need to reference an ivar in your block, either use a property instead or use bself->ivar.


Addendum: When compiling as ARC, __block no longer breaks retain cycles. If you're compiling for ARC, you need to use __weak or __unsafe_unretained instead.

objective c missing _block type specifier

Your assignments to your two string variables are inside a block you pass to sendTwitterRequest:completion:. By default a block captures the value of any local variables it uses declared outside the block, in your case r1 and r2, it does not capture the variables themselves, which means it cannot alter the values stored in those variables. Note that if the value captured is a reference to a mutable object, in your case the values are references to mutable strings, then you can mutate the object - doing that does not alter the reference itself.

You can fix your code in two ways:

1) I think the values you are trying to assign are references to immutable strings, NSString *, so I suspect you have only declared the two variables as NSMutableString * in an attempt to fix your problem.

To allow assignment to captured local variables you must annotate the local variable declaration with __block, this changes the behaviour capture so that the variable, rather than its value, is captured. To go this route you just need to change your declarations to:

__block NSString *r1;
__block NSString *r2;

There is no need to give the variables an initial value, they will automatically have the value nil. Your block can now assign directly to r1 and r2, however see the BIG BUT below.

2) If you do require mutable strings, NSMutableString *, then your two declarations are fine and the issue is that you use assignment to the variables (r1 & r2) instead of mutating the strings they reference. You can change the value of a mutable string using setString: (Apple documentation. To do this replace your two assignments with:

[r1 setString:json[@"statuses"][0][@"text"]];
[r2 setString:json[@"statuses"][1][@"text"]];

These two will mutate your strings referenced by variables and those changes will be visible outside your block via the references stored in r1 and r2. However as with the first method above see the following BIG BUT...

BIG BUT

The code fragment you supply suggests you might also be making a common error: assuming values assigned within a block used as an asynchronous handler will be visible after the call taking the block, in your case sendTwitterRequest:completion:. This will normally not be true, the call to sendTwitterRequest:completion: returns before the completion block has run - which is the whole point of asynchronous methods such as sendTwitterRequest:completion:; they schedule the work (accessingTwitter in your case) to run concurrently in the background and then return, later when the asynchronous work is completed the completion block is called.

If you have made this error you need to read up on asynchronous design, you can use Apple's documentation if you wish, you can also search on SO - there are plenty of Q & A on the topic. After that is done you can redesign your code, if you have problems at that point ask a new question.

HTH

How to detect if a block of memory already freed

First, you need to be aware that the function free(p) will just flag a block of memory to be available for any new allocation, that's it, nothing else; While your pointer p still Valid, and you can Read and Write using it even if the block is already freed.

About your question "How to detect if a block of memory is already freed?" the short answer in C is there is no standard way. But you can write your own pointer-tracker to detect if a block of memory is already freed, which is not hard to do, this is an example:

void *ptr_list[64];
int ptr_position = 0;

bool ptr_exist(void *p) {
if(p == NULL)
return false;
for(int i = 0; i < ptr_position; i++) {
if(ptr_list[i] == p)
return true;
}
return false;
}

void ptr_add(void *p) {
if(p == NULL)
return;
if(!ptr_exist(p)) {
for(int i = 0; i < ptr_position; i++) {
if(ptr_list[i] == NULL) {
ptr_list[i] = p;
return;
}
}
ptr_list[ptr_position] = p;
ptr_position++;
}
}

void ptr_free(void **p) {
if(*p == NULL)
return;
for(int i = 0; i < ptr_position; i++) {
if(ptr_list[i] == *p) {
ptr_list[i] = NULL;
}
}
for(int i = ptr_position; i >= 0; i--) {
if(ptr_list[i] == NULL) {
ptr_position = i;
break;
}
}
free(*p);
*p = NULL;
}

To use it, simply after you allocate a block of memory add your pointer to the tracker using ptr_add(), and when you want to free it, use ptr_free(). Finally you can check at any moment from any thread if this block of memory still valid or not using ptr_exist().

Full code :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

// -- Pointers Tracker --
void *ptr_list[64];
int ptr_position = 0;

bool ptr_exist(void *p) {
if(p == NULL)
return false;
for(int i = 0; i < ptr_position; i++) {
if(ptr_list[i] == p)
return true;
}
return false;
}

void ptr_add(void *p) {
if(p == NULL)
return;
if(!ptr_exist(p)) {
for(int i = 0; i < ptr_position; i++) {
if(ptr_list[i] == NULL) {
ptr_list[i] = p;
return;
}
}
ptr_list[ptr_position] = p;
ptr_position++;
}
}

void ptr_free(void **p) {
if(*p == NULL)
return;
for(int i = 0; i < ptr_position; i++) {
if(ptr_list[i] == *p) {
ptr_list[i] = NULL;
}
}
for(int i = ptr_position; i >= 0; i--) {
if(ptr_list[i] == NULL) {
ptr_position = i;
break;
}
}
free(*p);
*p = NULL;
}
// ----------------------

void free_block(u_int8_t *block) {

// Info
printf("free_block()\t-> %p Point To %p \n", &block, block);

// Free Block
// free(block);
// block = NULL;
ptr_free((void *)&block);
}

void print_block(u_int8_t *block) {

// Detectc if this block is freed
// This is the objective of this code
if(!ptr_exist(block)) {

printf("print_block()\t-> %p Is Null.\n", block);
return;
}

// Info
printf("print_block()\t-> %p Point To %p -> ", &block, block);

// Print byte by byte
u_int8_t *p = block;
for(int i = 0; i < 3; i++) {

printf("0x%02X ", *(u_int8_t *)p);
p++;
}
printf("\n");
}

int main(void) {

// Allocat a block in the memory
u_int8_t *block = malloc(3 * sizeof(u_int8_t));

// Add it to the tracker
ptr_add((void *)block);

// Set all to zeros
memset(block, 0x00, 3);

// Info
printf("Main()\t\t\t-> %p Point To %p \n", &block, block);

// Print the block content
print_block(block);

// Free the block
free_block(block);

// Print the block content gain
// This shold print Null because
// we freed the block.
print_block(block);

return 0;
}

Cast closures/blocks

How about a generic Block parameterized with the function type?

class Block<T> {
let f : T
init (_ f: T) { self.f = f }
}

Allocate one of these; it will be a subtype of AnyObject and thus be assignable into dictionaries and arrays. This doesn't seem too onerous especially with the trailing closure syntax. In use:

  5> var b1 = Block<() -> ()> { print ("Blocked b1") }
b1: Block<() -> ()> = {
f = ...
}
6> b1.f()
Blocked b1

and another example where the Block type is inferred:

 11> var ar = [Block { (x:Int) in print ("Block: \(x)") }]
ar: [Block<(Int) -> ()>] = 1 value {
[0] = {
f = ...
}
}
12> ar[0].f(111)
Block: 111


Related Topics



Leave a reply



Submit