Don’t confuse a “Block” with “Delegation”. Delegation is a commonly used design pattern in iOS and OSX (Cocoa). A “Block” is a feature added to objective C a few years ago and it’s similar to a function pointer in C, with some marked differences.
A “Block”, as the name implies, allows you (amongst other things) to pass a block of code as an argument to a method. The receiver of the method can then choose to hang on the block of code, and run it at a later time. Now, because the method in which the block was passed as an argument might go out of scope before the block has a chance to execute, the block is copied to the heap, and the address of where it exists on the heap is passed as the argument. This allows the class that receives the address of the block, which now exists in the heap, to call the block at any time. This is one of the reasons that a block strongly captures any variables that are within its scope (unless that variable was preceded by the __block specifier). Blocks are a powerful and flexible feature that takes a bit of time (and practice) to truly understand.
“Delegation” on the other hand is more of a process or concept. When you set the “delegate” property of a class, you’re basically committing to have the class that was set as the delegate, to implement certain method(s). These “methods” depend on what protocol (bunch of declared methods) that the delegate is expected to conform to (i.e. promise to implement).
The reason you may mix up the concept of Blocks and Delegation is because both can be used as callback mechanisms.
To simplify it. A “Block” allows you to pass a set of instructions (block of code) to another class that may execute that code at a later time. Delegation allows you to pass a reference to a class (the “delegate”) that promises to implement a bunch of methods that may be called by another class. Passing the reference, allows the other class to call back and execute any agreed upon methods. These agreed upon methods may be mandatory or optional. This implies that the delegate must be around before the “delegator” can call it. That limitation does not necessarily exist with a block, as the block is copied to the heap. The class that receives the reference to the block is able to call the block, without requiring the class that passed the block to it to be around.
In your mentioned example code, commenting out the line “self.imagePopover.delegate = self;” prevents the UIPopoverController instance class, that is referenced by self.imagePopover, from having a reference or a handle to “self”, so self.imagePopover will not be able to call any of the UIPopoverControllerDelegate declared methods. In fact, many times I’ve committed the mistake of implementing a bunch of protocol/delegate methods only to find that none of those methods are being called. After examining my code I notice that I forgot to set the delegate property, so the “delegator” was unable to call “self”.
Try this, place a NSLog message in the delegate methods - (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController, while commenting out the line “self.imagePopover.delegate = self”. Run the app, trigger the popover and then dismiss it. Do the same steps, this time uncomment “self.imagePopover.delegate = self” line, and pay attention to the messages in the debugger console. You’ll notice that when you set “self” as the delegate, then “self” will receive the delegate/callback methods from the instance of UIPopoverController class.
Hope that clearer than mud