Objective c block in a block - ios

Lot of blocks here!
I am trying to use blocks to perform an operation on each record present in a dictionary.
I created a weak reference of the strongRecordBlock and used that to call itself in the strongRecordBlock. It all worked fine until I introduced my actual operation (DataManager addRecord) that I need to perform which in turn is a block.
So there is an exception now, the weakRecordBlock is null after first iteration of the recursive loop. Can anybody please guide!
__weak __block void (^weakRecordBlock)(int i);
void (^strongRecordBlock)(int) = ^(int i) {
NSString *key = weakSelf.recordDictionary.allKeys[i];
CSVRecord *record = [weakSelf.recordDictionary objectForKey:key];
NSLog(#"%d %#", i, record.recordFullname);
[[DataManager sharedInstance] addRecord:record onSuccess:^(NSString *objectId) {
if (i < weakSelf.recordDictionary.allKeys.count-1) {
weakRecordBlock(i+1);//Crashes here
}
else {
completedBlock();
}
} onError:^(NSError *error) {
onError(error);
}];
};
weakRecordBlock = strongRecordBlock;
strongRecordBlock(0);

The problems is that you are trying to use weak pointer inside of block. And it lead to realising weak point after first run loop.
So you need to create strong reference to the weakRecordBlock inside of strongRecordBlock. So just add this line of code on top of your strongRecordBlock
void (^strongPointerToWeakRecordBlock)(int i) = weakRecordBlock;
and replace weakRecordBlock(i+1) with strongPointerToWeakRecordBlock(i+1)

RomanSalabay's answer is right. The problem is -[DataManager addRecord:record onSuccess:] executes its argument block asynchronously. Therefore, that block (the argument to -[DataManager addRecord:record onSuccess:]) needs to keep a strong reference to the objects and blocks used within, to keep them alive until the block runs; otherwise they can be deallocated by the time that block runs. But it captures a weak reference (weakRecordBlock). It needs to copy a strong reference instead. So you should assign the weak variable to a strong variable in the body of the outer block to let the inner block capture.

Related

Modifying global variables in Objective-C blocks

So I have an instance function that takes in an NSInteger as a parameter; and in the function, I have a block. I need to modify the NSInteger that gets passed into the function. But it isn't a __block type. How should I go about doing that?
The original function is too complicated so I'll just put a simplified version here...
//#interface
#property(nonatomic) NSInteger input;
...
//#implementation
[self doThis:self.input];
-(void)doThis:(NSInteger)integer{
[API doSomethingWithThisInteger:integer success:^(NSMutableDictionary *data){
...
} failure:^(NSString *error){
integer--;
}
}
I know that I'm supposed to pass in a __block type variable but if I initialized a new one in the function (i.e. __block NSInteger temp = integer) and put temp-- instead of integer-- in the failure block, then self.input would remain the same since the initialization statement copies the value of input instead of referencing to it. What should I do here? Is there a way to make the new variable a reference to the variable I pass into the function? Thanks!
EDIT: solution to problem -
Used a global variable instead of a property -
#implementation
NSInteger input;
....
[self doThis:&input]; //sends in the address of the input
....
- (void)doThis:(NSInteger *)integer{ //takes the pointer of the input instead of its actual value so it gets referenced rather than getting copied
[API doSomethingWithThisInteger:integer success:^(NSMutableDictionary *data){
...
} failure:^(NSString *error){
*integer = *integer - 1; //dereference the pointer to get the value.
}
You have to give a block some reference to variable to modify. By calling doThis: you pass an integer by value (not by reference), so failure block gets effectively just a copy of integer value - so original variable has no chance to get modified.
The same is valid for __block NSInteger temp = integer - temp gets a copy of an integer. Block can modify temp, however it's just a copy of integer - so no chance to change the original value.
To get the value changed, use:
-(void)doThis
{
[API doSomethingWithSuccess:^(NSMutableDictionary *data)
{
...
}
failure:^(NSString *error)
{
self.input--;
}
}
This way you get a reference to input via self. However, it's considered bad in ARC environment because self gets impliciltly captured by the block and this may lead to retain cycle. So, the best way is create weak reference to self and let it get captured by the block:
-(void)doThis
{
__weak typeof(self) weakSelf = self;
[API doSomethingWithSuccess:^(NSMutableDictionary *data)
{
...
}
failure:^(NSString *error)
{
weakSelf.input--;
}
}
P.S. Your question effectively discloses, that you have no idea, how it works - pointers, passing parameters by value/by reference, ObjC blocks etc. You should get more theoretical knowledge about your programming language to avoid such questions in future.
Objective-C, like C, passes everything by value. It welds objects on top of C by putting them on the heap and referring to them by pointer. So what you're passing around isn't the object itself, it's the address of the object. The address itself is passed by value. But if someone knows the address, they can go to the heap and modify the object.
Your input to doThis: is a parameter, integer. So when calling that method what will have happened is:
whatever you wrote where the parameter should be will be evaluated and, if necessary, implicitly cast to `NSInteger';
a copy of that NSInteger will be supplied to the method;
having received its own copy, integer is now equivalent to a local variable for the method.
So e.g. you could do:
[object doThis:8];
The 8 is copied into what is effectively a local variable within doThis:, so you can modify integer all you like regardless of the fact that you passed in a constant.
If you want doThis: to be able to modify the integer then you need to supply a pointer to it. And once you have that you should have no problem using that pointer inside a block. The pointer itself will be captured but, as when passing a pointer into a method, if you modify what the pointer points to then that will effect everybody else that looks there.

Callback from inside a block (Objective C)

I have this method with a block in it, I want it to send the userID to another method as soon as it exists. userID is a value that is parsed from the internet, so it usually takes about 2 seconds to load up and 'exist'. Is there any way I can do a 'when userID exists, send it to another method?
Here's all my code:
- (void)parseForUserID {
//Get the Data you need to parse for (i.e. user main page returned as a block of NSData.
TClient *client = [[TClient alloc] init];
[client loginToMistarWithPin:#"20014204" password:#"yuiop" success:^{
[client getUserID:^(NSString *result) {
NSString *userIDWithHTML = [self userIDRegex:result];
NSString *userID = [self onlyNumbersRegex:userIDWithHTML];
//if userID exists, send it to another method in a different class
}];
} failure:^{
NSLog(#"login failed from controller");
}];
}
I see that this is the third question you ask related to the same issue, so I guess you're having some trouble understanding blocks.
First you have to understand that the block, in a certain sense, can be seen as a function. The difference is that, unlike a function, the block has no name, and instead of using function's name you just place the code inline where you need it.
Second thing to understand is that a block is usually used as a callback. Other callback mechanisms are function pointers and delegates. When you pass a block as a parameter to a function you're basically telling the function: "Hey, when certain conditions are met, execute this little code for me, please"
Third think to understand is if the block (or any callback) will be called synchronously. Actually this has nothing to do with the block itself, per se, but rather with the function being called. If the function is asynchronous, the function will create another thread and return immediately to execute the next line after the one that invoked the asynchronous function. Meanwhile the new thread will execute some code (the body of the async function) and, eventually execute the block passed as parameter, and finally the thread is killed and doesn't exist any more. (Note: There's no way to know if a function is synchronous or asynchronous other that reading the documentation for such a function).
Now let's go back to your code.
[client loginToMistarWithPin:#"20014204" password:#"yuiop" success:^{
[client getUserID:^(NSString *result) {
NSString *userIDWithHTML = [self userIDRegex:result];
NSString *userID = [self onlyNumbersRegex:userIDWithHTML];
// PLACE HERE THE CODE TO EXECUTE WHEN SUCCESSFULLY LOGGED IN
[anotherClassInstance someMethod:userID];
}];
} failure:^{
NSLog(#"login failed from controller");
}];
Everything that should be executed once the user logged in should be placed inside the block (if the function is synchronous you could place it after the block). To send the userID to another class, just call that class' method as you would in any other part of your code.
In my opinion using a delegate is not necessary (although only you would know, since you're the architect of your app).
As #santhu said, use either the delegate pattern or notification pattern. It's also a common practice to use both of them. Usually a delegate is the correct approach but sometimes you need a notification. Using both covers all your bases.
Look them up before deciding which and for full details on how they work, but basically:
[client getUserID:^(NSString *result) {
NSString *userIDWithHTML = [self userIDRegex:result];
NSString *userID = [self onlyNumbersRegex:userIDWithHTML];
// delegate pattern:
if ([self userIdIsValid:userID]) {
if (self.delegate && [self.delegate respondsToSelector:#selector(foundValidUserID:)]) {
[self.delegate foundValidUserID:userID];
}
} else {
if (self.delegate && [self.delegate respondsToSelector:#selector(foundInvalidUserID:)]) {
[self.delegate foundInvalidUserID:userID];
}
}
// notification pattern:
if ([self userIdIsValid:userID]) {
[[NSNotificationCenter defaultCenter] postNotificationName:MyFoundValidUserIDNotification object:self userInfo:#{#"userID": userID}];
}
} else {
[[NSNotificationCenter defaultCenter] postNotificationName:MyFoundInvalidUserIDNotification object:self userInfo:#{#"userID": userID}];
}
}];
There is a third option, which is you could use a block callback... this is how the new kids on the block do it... there's no well defined pattern here, blocks are brand new and delegates/notifications are 20 years old. But here's how I'd use a block to define a callback:
typedef void (^UserIdCallbackBlock)(NSString *userID);
- (void)parseForUserIDOnSuccess:(UserIdCallbackBlock)successCallback onFailure:(UserIdCallbackBlock)failureCallback {
...
NSString *userID = [self onlyNumbersRegex:userIDWithHTML];
if ([self userIdIsValid:userID]) {
successCallback(userID);
} else {
failureCallback(userID);
}
...
}
I would like to give a hint regarding your comment:
for code readability, it's not that I just have one more task to do, the thing I put inside this block will also have a block and another block and another.
This is a typical asynchronous pattern - called "continuation".
Given, that you should also implement proper error handling and that you should also provide a means to cancel that whole "chain" of asynchronous tasks at any point, the typical solutions with NSOperationQueues and NSOperations, dispatch_queue and blocks, NSNotifications or delegates will inevitable become unduly elaborate, complex and difficult to comprehend by others. (There's already an answer here that demonstrates this grandiose ;) )
So, whenever problems become more complex and the "built-in frameworks" don't provide a comfortable solution, third party libraries come into play to help you.
But first, lets have a non-trivial example, based on your comment:
it's not that I just have one more task to do, the thing I put inside this block will also have a block and another block and another
OK, lets suppose your objective is actually:
Asynchronously perform a Login for a web service.
Then, if that succeeded, asynchronously fetch a list of objects as JSON.
Then, if that succeeded, parse the JSON response.
Then, if that succeeded, insert the objects into a managed object context and asynchronously save the chain of managed object contexts and make it persistent.
When this all above succeeded, update the UI on the main thread
If anything fails, report the error of the task that failed
I will show how a solution utilizing a library implementing "promises" (see wiki Future and promises) may look like:
Without further ado, and without thorough explanation what that "Promise" is about, suppose we have a method defined in your View Controller, which is declared:
- (RXPromise*) loginToMistarWithPin:(NSString*)pin
password:(NSString*)password;
Note: The above method is asynchronous and it is functional equivalent to the form:
typedef void (^completion_t)(id result, NSError*error);
- (void) loginToMistarWithPin:(NSString*)pin
password:(NSString*)password
completion:(completion_t)completion;
then suppose we have another method in your View Controller, fetching objects from a remote server (asynchronous as well):
- (RXPromise*) fetchObjects;
Then, suppose we have a class CoreDataStack which consists of a "root context" saving to the persistent store having a child managed object context, the "main context", which is associated to the main thread.
The class CoreDataStack defines this method, which saves a chain of managed object contexts, which is basically setup: childContext -> main_context -> root_context:
- (RXPromise*) saveWithChildContext:(NSManagedObjectContext*)childContext;
Then, the whole task as stated in the steps 1. through 5. can be expressed as follows:
[client loginToMistarWithPin:#"20014204" password:#"yuiop"]
.then(^id(id result){
// login succeed, ignore result which is #"OK"
// Now fetch the objects with an asynchronous network request,
// returning JSON data as a NSData object when it succeeds:
return [client fetchAllUsers];
}, nil)
.then(^id(NSData* json){
// The network request succeeded, and we obtain the JSON as NSData.
// Parse it and get a Foundation representation:
NSError* error;
id jsonArray = [NSJSONSerialization JSONObjectWithData:json
options:0
error:&error];
if (jsonArray) {
return jsonArray; // handler succeeded
}
else {
return error; // handler failed
}
})
.then(^id(NSArray* objects){
// Parsing succeeded. Parameter objects is an array containing
// NSDictionaries representing a type "object".
// Save into Core Data:
// Create a managed object context, which is a child of the
// "main context" of a Core Data stack:
NSManagedObjectContext* moc = [[NSManagedObjectContext alloc]
initWithConcurrencyType:NSPrivateQueueConcurrencyType];
moc.parentContext = self.coreDataStack.managedObjectContext;
// Create managed objects and initialize them with the given
// NSDictionary:
for (NSDictionary* object in objects) {
// note: `createWithParameters:inManagedObjectContext` executes on
// the context's queue
[Object createWithParameters:object inManagedObjectContext:moc];
}
// Finally, asynchronously save into the persistent store and
// return the result (a RXPromise):
return [self.coreDataStack saveWithChildContext:moc];
}, nil)
.thenOn(dispatch_get_main_queue(), ^id(id result){
// Saving to the backing store succeeded. Now, we possibly want to
// update some UI on the main thread. We are executing on the main
// thread already (see thenOn(dispatch_get_main_queue())
...
[self.tableView reloadData];
return nil;
}, nil)
.then(nil, ^id(NSError* error){
// If something went wrong in any of the above four steps, the error
// will be propagated down and "cought" in this error handler:
NSLog(#"Error: %#", error);
});
Disclaimer: I'm the author of the library RXPromise available at GitHub. There are a few more Objective-C libraries which implement Promises.

Block recursion and breaking retain cycle

To better illustrate the question, consider the following simplified form of block recursion:
__block void (^next)(int) = ^(int index) {
if (index == 3) {
return;
}
int i = index;
next(++i);
};
next(0);
XCode (ARC-enabled) warns that "Capturing 'next' strongly in this block is likely to lead to a retain cycle".
Agreed.
Question 1: Would the retain cycle be successfully broken by setting the block itself to nil, in this fashion:
__block void (^next)(int) = ^(int index) {
if (index == 3) {
next = nil; // break the retain cycle
return;
}
int i = index;
next(++i);
};
next(0);
(Note: you'd still get the same warning, but perhaps it is unwarranted)
Question 2: What would be a better implementation of block recursion?
Thanks.
To accomplish the retain-cycle-free recursive block execution, you need to use two block references - one weak and one strong. So for your case, this is what the code could look like:
__block __weak void (^weak_next)(int);
void (^next)(int);
weak_next = next = ^(int index) {
if (index == 3) {
return;
}
int i = index;
weak_next(++i);
};
next(0);
Note that the block captures the weak block reference (weak_next), and the external context captures the strong reference (next) to keep the block around. Both references point to the same block.
See https://stackoverflow.com/a/19905407/1956124 for another example of this pattern, which also uses block recursion. In addition, the discussion in the comments section of the following article is relevant here as well: http://ddeville.me/2011/10/recursive-blocks-objc/
I think #newacct is correct about #Matt Wilding's solution; it does seem that nothing will have a strong ref to the next block in that case and will result in a run time exception when run (at least it did for me).
I don't know how common it is to find recursively called blocks in the wild in objc. However, in a real world implementation (if actually required) on say, a view controller, one might define the block and then set up an internal interface property with a strong reference to said block:
typedef void(^PushButtonBlock)();
#interface ViewController ()
#property (strong, nonatomic) PushButtonBlock pushButton;
#end
#implementation ViewController
...
// (in viewDidLoad or some such)
__weak ViewController *weakSelf = self;
self.pushButton = ^() {
[weakSelf.button pushIt];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), weakSelf.pushButton);
};
self.pushButton();
...
#end
This runs fine for me and has no compiler warnings about retain cycles (and no leaks in instruments). But, I think I would probably steer clear of doing this (recursive block calls) in most cases in objc - it's smelly. But interesting in any case.

questions/problems while implementing reusable thread-safe core data pattern

I'm having trouble implementing the thread-safe core data concepts outlined in this tutorial. My goal is to have a reusable portion of code that can take arguments in, do core data operations (adds, updates, deletes) and then callback asynchronously when done.
So heres the block that 'safely' modifies core data objects:
+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock
{
NSManagedObjectContext *context = [NSManagedObjectContext context];
[context setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
[defaultContext setMergePolicy:NSMergeObjectByPropertyStoreTrumpMergePolicy];
[defaultContext observeContext:context];
 
block(context);
if ([context hasChanges])
{
[context save];
}
}
From the way I understand it, this executes a block of code? I don't understand how the 'context' being passed in figures in. Is this part of the block's signature?
So here is the wrapper that does the operation in the background and adds a completion call:
+ (void)saveDataInBackgroundWithContext:(void(^)(NSManagedObjectContext *context))saveBlock completion:(void(^)(void))completion
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
[self saveDataInContext:saveBlock];
dispatch_sync(dispatch_get_main_queue(), ^{
completion();
});
});
}
Here is an example using it:
NSArray *listOfPeople = ...;
[NSManagedObjectHelper saveDataInBackgroundWithContext:^(NSManagedObjectContext *localContext){
for (NSDictionary *personInfo in listOfPeople)
{
PersonEntity *person = [PersonEntity createInContext:localContext];
[person setValuesForKeysWithDictionary:personInfo];
}
} completion:^{
self.people = [PersonEntity findAll];
}];
What is the 'localContext' passed in here? I think most of my issues here revolve around not understanding blocks.
A brief look at that tutorial shows it is talking about magical record. I have never used it, so I can't speak for it.
// This declares a class method that returns void and takes a block as parameter.
// The block returns void and has one parameter, namely, a pointer to an
// NSManagedObjectContext object.
+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock;
You would call that method like this...
[SomeClass saveDataInContext:^(NSManagedObjectContext *context){
// Some code
}];
That means you are passing in a block of code to the function. At some point it will execute the bock of code you gave it. When it does, it's going to pass a managed object context into the block so it can do something with it.
Now, look at the implementation of that method...
+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock
{
// Create a MOC - note there is no concurrency type, so it will get
// NSConfinementConcurrencyType, which means it must be used exclusively
// from the thread in which it was created. Since it is a local variable
// and it gets destroyed after this function is called, that should be cool
// PROVIDED the using block does not do anything untoward with it.
NSManagedObjectContext *context = [NSManagedObjectContext context];
// Set the merge policy
[context setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
// MR must set some default context...
// Some how the above context needs a persistent store to save...
[defaultContext setMergePolicy:NSMergeObjectByPropertyStoreTrumpMergePolicy];
// Probably setting up notification handler for DidSave
[defaultContext observeContext:context];
// Now, this is where the block you passed in gets called.
// Note, that the managed object context has already been setup for you.
// Now that it's setup, the block of code that you passed in is going
// to be called, and it will be given a context that it can use to execute
// code in the calling thread.
block(context);
// If you changed something to the context in your block of code, the save.
if ([context hasChanges])
{
[context save];
}
}
Let's revisit a our code that called this method...
[SomeClass saveDataInContext:^(NSManagedObjectContext *context){
// Now, the saveDataInContext method has been called. However, inside
// that method, a call was made to the block that was passed in.
// That would be this here block of code. So, if you look up in
// the method, where is calls "block(context)" this block of code will
// be executed right there. Mentally, you can cut and paste this code
// in that spot.
// The context parameter is the context that was passed to this block.
// you can use it to do any Core Data stuff...
}];
Now, this code is very similar, but it takes two blocks. One is used to execute some code on the context, and the other is a block that will get executed with the asynchronous save has completed.
saveBlock should be familiar. It's the same concept as in the above example.
completion is a block, that returns void, and takes not parameters. It will get called when all the work has been done.
+ (void)saveDataInBackgroundWithContext:(void(^)(NSManagedObjectContext *context))saveBlock completion:(void(^)(void))completion
{
// Dispatch some work on one of the global concurrent queues. It will
// get done on some thread, nobody knows which one, but it does not matter
// because the code in this block calls saveDataInContext, and passes the
// block it was given that does some modifications to the context.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
[self saveDataInContext:saveBlock];
// Now, when the above work is done, we are still running in some random
// thread. I guess the library wants all callbacks to happen on the main
// thread, so this block is dispatched on the main thread. Note that it
// calls the second bock passed in as the completion block.
// So the <saveBlock> will be run on some random thread, and then, when
// it is done, the <completion> block will be called on the main thread.
dispatch_sync(dispatch_get_main_queue(), ^{
completion();
});
});
}
Like earlier, when you call that method, you can mentally replace the with the first block you pass in, and replace with the second block.
[NSManagedObjectHelper saveDataInBackgroundWithContext:^(NSManagedObjectContext *localContext){
// This is the first block. It gets executed where you see <saveBlock>
// being used in the earlier method. You are being given the already
// prepared MOC, and it's name is <localContext>. Do your managed object
// context stuff with it. Note that it will be running in some unknown thread.
for (NSDictionary *personInfo in listOfPeople)
{
PersonEntity *person = [PersonEntity createInContext:localContext];
[person setValuesForKeysWithDictionary:personInfo];
}
} completion:^{
// Now, this is the second block, which is run when all the core data saving
// has been completed. It will run on the main thread.
self.people = [PersonEntity findAll];
}];
Hopefully, that helps you understand what is happening, even though I don't know what magical record is really doing under the covers.
EDIT
In response to this comment...
I don't think I understand how these blocks work. If a block has this
method signature "+
(void)saveDataInContext:(void(^)(NSManagedObjectContext
*context))saveBlock" why is the block NOT using "context" or "saveBlock"? Which is the return value for a block and which is the
passed in value? – Mike S
First, the block does not have this signature...
+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock;
That is a class method. Let's break it down piece by piece. First, however, let's forget the block parameter, and use something easy, for comparison.
+ (void)foo:(NSInteger)someInteger;
That is a is a class method, foo:, which returns void and takes one argument. The type of that single argument is NSInteger. If I wanted to call it, I would do so like this:
[SomeClass foo:42];
Likewise...
+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock;
is a class method, saveDataInContext:, which returns void and takes one argument. The type of that single argument is void(^)(NSManagedObjectContext *context).
Now, don't let that gobbly-dee-gook fool you. It's just a type (albeit a somewhat confusing one to parse if you don't understand much C) So, what is void(^)(NSManagedObjectContext *context)
First, it is a block. If that (^) after the void were (*) it would be a function pointer.
Basically, it means that the type of that argument is a block that returns void and has one parameter, namely a pointer to a NSManagedObjectContext (with a name context).
So, if we read it out loud...
+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock;
is a class method, with selector saveDataInContext: which returns void and has one parameter, which has a name saveBlock and is of the type "block that returns void and has one parameter of type NSManagedObjectContext *."
Just like we call the first example like this...
[SomeClass foo:42];
we call the latter example like this...
[SomeClass saveDataInContext:^(NSManagedObjectContext *context){
// We are creating a bock of code, so stuff some code in here.
}];
Now, just like you passed the integer 42 to foo: you are passing the block in between the {} as the argument to saveDataInContext:.
Now, note that the signature of thesaveDataInContext: method wants a block that itself has a parameter. So, when you provide your block, you are basically saying, "Hey, here is a block of code for you to call, and when you do so, make sure you give me a pointer to a NSManagedObjectContext object that I can use.
What this means is that when your block is called, the calling code will call your block and provide a NSManagedObjectContext * to you with the variable name context.
Think of it like this, as a trivial example of saveDataInContext:.
+ (void)saveDataInContext:(void(^)(NSManagedObjectContext *context))saveBlock {
// Create a context to give the block we are going to call..
NSManagedObjectContext *moc = //
saveBlock(moc);
}
Now, when your code is called, you will get the moc object as your argument. Bascially, that method creates a managed object context, does all the thread safety stuff, then calls your block of code, and gives you a pointer to the managed object context that it has safely created. Your code is executed within the confines of that safe environment, using the MOC passed to it as a function (block) parameter.
I hope that didn't make it worse...

Initializing an object inside a block

I'm trying to initialize a dict variable but I don't understand why one way works, while the other does not.
In case 1 everything is alright and I can use dict later.
In case 2 it will be released very soon (It will becomes a zombie) and If I try to use it later (outside a block) the program crashes.
Here's some code from my class (c++ mixed with objective-c) written for ios.
Inside the block i tried to initialize variable dict in two different ways.
class Data
{
public:
NSMutableDictionary *dict;
void DoSomeStuff()
{
[NSSomeFrameworkTool doSomeStuffWithCompletionHandler:^(NSError *err) {
// case 1 - OK
dict = [[NSMutableDictionary alloc] initWithDictionary:[NSKeyedUnarchiver unarchiveObjectWithFile:#"dict.dat"]];
// case 2 - will crash later if i try to use dict
dict = [NSKeyedUnarchiver unarchiveObjectWithFile:#"dict.dat"]; }];
}
}
This class has class variable dict, which is initialized in the DoSomeStuff() method.
That method calls a method from the ios framework that uses block (as a callback) to inform me that some task is done.
I was wondering why case 1 and case 2 work different. Maybe it is forbidden to use references outside the block, that was initialized inside this block?
What's wrong with doing this the way shown in case2?
In first case you don't release your dict, and in second case it is autoreleased so you should retain it.
dict = [[NSKeyedUnarchiver unarchiveObjectWithFile:#"dict.dat"] retain];
I think you can use a block variable here.
__block NSMutableDictionary *dict;
Variables are immutable inside of the block. They are a constant copy, a snapshot of the variable at the time of "block creation" so it can not be modified inside the block. The block variable will move the variable to the 'Heap' from the 'Stack' allowing you to change it's state. I'm by no means an expert on blocks, being that they are relatively new to Objective c.But there are some good articles if you google around to learn from.
http://pragmaticstudio.com/blog/2010/7/28/ios4-blocks-1

Resources