Does calling a protocol method pass program flow control? - iphone

I know this is quite possibly a lame question, but I've pulled three consecutive all-nighters and I'm very blurry. And I'm new to Objective C and Cocoa Touch.
I've created a class that provides a delegate method. I'll use simplified example code since the specifics aren't important. The header file looks like this:
#import <Foundation/Foundation.h>
#protocol UsernameCheckerDelegate <NSObject>
#required
- (void)didTheRequestedThing:(BOOL)wasSuccessful;
#end
#interface TheDelegateClass : NSObject {
id <TheDelegateClassDelegate> tdcDelegate;
}
#property (assign) id <TheDelegateClassDelegate> tdcDelegate;
- (void)methodThatDoesSomething:(int)theValue;
#end
And the source file looks like this:
#import "TheDelegateClass.h"
#implementation TheDelegateClass
#synthesize tdcDelegate;
- (void)methodThatDoesSomething:(int)theValue {
if (theValue > 10) {
[[self tdcDelegate] didTheRequestedThing:NO];
// POINT A
}
// POINT B
int newValue = theValue * 10;
NSString *subject = [NSString stringWithFormat:#"Hey Bob, %i", newValue];
// Some more stuff here, send an email or something, whatever
[[self tdcDelegate] didTheRequestedThing:YES];
// POINT C
}
#end
Here's my question: if theValue is in fact greater than 10 and the line above POINT A runs, does program flow control pass out of this method (and back to the didTheRequestedThing delegate method in the object that called this) or does flow continue on through POINT B to POINT C?
I'm hoping for the former because I can simplify the heck out of my code, currently an unpleasant mess of deeply nested ifs and elses.

When the -didTheRequestedThing: method returns, control flow returns back to your POINT A and continues on to POINT B and POINT C. Delegate method calls are exactly like any other method call. If you want to avoid executing the rest of the method after the delegate call, just stick a call to return where your // POINT A comment is.

Related

Is it safe to store an objective-c block in a std::function?

I would like to pass a callback block from my objective-C++ code to a C++ object. It's very straightforward since I'm able to assign a block to a std::function. In my mini example everything worked fine, but I'm still uncertain if it's safe to do that.
#import "ViewController.h"
#include <functional>
std::function<void(void)> f;
#interface T : NSObject
#property (strong) NSString* value;
#end
#implementation T
- (void)dealloc {
NSLog(#"dealloc");
}
#end
#implementation ViewController
- (IBAction)storeBlock:(UIButton *)sender {
T* t = [[T alloc] init];
t.value = #"the captured obj";
f = ^void(void) { NSLog(#"This is the block with %#", t.value); };
}
- (IBAction)useBlock:(UIButton *)sender {
f();
}
- (IBAction)releaseBlock:(UIButton *)sender {
f = nullptr;
}
#end
I've learned that the blocks are stored on the stack and I have to copy it to the heap if I want to use it further than the scope of the block's creation (which I haven't done in my example explicitly). I'm also uncertain how ARC can handle this situation. Is it 'officialy' allowed to do this? I'm using Xcode 9.2.
Objective-C blocks become invalid when execution leaves the scope where the block is defined. To avoid this, the copy method must be used on the block, that's all.
Blocks are treated like normals objects despite the fact, that they start their lifetime on the stack. Like you said, in objc-cpp we can easily store a block in a std::function :-)
So what happens in your example?
You declared the std::function "f" as a global stack object. When the block is assigned to it, the reference count from the block object is 1. Your "T"-object has in the storeBlock function before leaving two references on it. One by "t" and one through the capturing mechanism from the block. Leaving the scope, only the blocks reference remains.
Then "f" is set to nullptr: There is no reference to the block object -> the block gets dealloced and with it the "T"-object, because it points a reference to it neither.

How to interact between classes

A very basic question on how to interact between classes here: how can I trigger an action called by clicking on a button linked to one class (the graphic user interface in my case - which does not contain any drawing code) inside another class (my drawing class - which is defined programmatically)?
Thanks!
Edited: I have tried to implement the solutions suggested below but I didn't manage to trigger the action from the other class. I have two classes: the main view controller and a class with the drawing code. Any advice would be highly appreciated. Thanks!
//MainViewController.m
//This class has a xib and contains the graphic user interface
- (void)ImageHasChanged
{
//do something on the GUI
}
//DrawView.m
//This class has no associated xib and contains the drawing code
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//I want to call ImageHasChanged from MainViewController.m here
//How can I do this?
}
Inter-class functionality is done simply by importing one class into the other, and calling an accessible method/instance variable on the import.
For the button IBAction example in your question:
ClassA.m (This will be imported via its header):
#import "ClassA.h"
#implementation ClassA
// This is a class-level function (indicated by the '+'). It can't contain
// any instance variables of ClassA though!
+(void)publicDrawingFunction:(NSString *)aVariable {
// Your method here...
}
// This is a instance-level function (indicated by the '-'). It can contain
// instance variables of ClassA, but it requires you to create an instance
// of ClassA in ClassB before you can use the function!
-(NSString *)privateDrawingFunction:(NSString *)aVariable {
// Your method here...
}
#end
ClassB.m (This is your UI class that will call the other method):
#import "ClassA.h" // <---- THE IMPORTANT HEADER IMPORT!
#implementation ClassB
// The IBAction for handling a button click
-(IBAction)clickDrawButton:(id)sender {
// Calling the class method is simple:
[ClassA publicDrawingFunction:#"string to pass to function"];
// Calling the instance method requires a class instance to be created first:
ClassA *instanceOfClassA = [[ClassA alloc]init];
NSString *result = [instanceOfClassA privateDrawingFunction:#"stringToPassAlong"];
// If you no longer require the ClassA instance in this scope, release it (if not using ARC)!
[instanceOfClassA release];
}
#end
Side note: If you're going to require ClassA a lot in ClassB, consider creating a class-wide instance of it in ClassB to re-use wherever it's required. Just don't forget to release it in dealloc (or maybe set it to nil in ARC) when you're finished with it!
Finally, please consider reading through the Apple Docs on Objective-C classes (and indeed all other sections of the documentation relevant to what you're trying to achieve). It is a bit time-consuming, but very well invested in the long run into building your confidence as an Objective-C programmer!
//As you said an instance of MainViewController has to be created first
MainViewController *instanceOfMainViewController = [[MainViewController alloc]init];
[instanceOfMainViewController ImageHasChanged];
//Thanks for your help Andeh!
Actually you can use #protocol(Delegate) to interact message between two classes this is standard way Or refer this document
http://developer.apple.com/library/ios/#documentation/General/Conceptual/CocoaEncyclopedia/DelegatesandDataSources/DelegatesandDataSources.html to learn more

How do i keep my code organised when my app needs a helper class?

I have a few custom UIViewControllers in my app which need to know the string returned of an NSDate. I could copy and paste the same code between these classes, but that's obviously terrible practise. It's also probably not good to put it in 1 class as a method, then have another class add this class to take advantage of it's method. It seems like a messy thing to do. So what would you recommend i do?
To clarify - I need a method which is given an NSDate and returns a string, for use in several other classes.
Sounds like you either need a function, rather than a method:
//Helpers.h
#import <Foundation/Foundation.h>
NSString * makeAStringFromThisDateSomehow(NSDate * d);
//Helpers.m
#import "Helpers.h"
NSString * makeAStringFromThisDateSomehow(NSDate * d)
{
// Body
// of
// your
// function
}
Or to make a category on NSDate to do what you need:
//NSDate+AndrewsCategory.h
#import <Foundation/Foundation.h>
#interface NSDate(AndrewsCategory)
- (NSString *)Andrew_MakeAStringSomehow;
#end
//NSDate+AndrewsCategory.m
#import "NSDate+AndrewsCategory.h"
#implementation NSDate(AndrewsCategory)
- (NSString *)Andrew_MakeAStringSomehow {
// Body
// of
// your
// method
}
#end
Note the stupid prefix on the method name. That's important to keep your method names from colliding with other method names on framework classes. Usually you would use initials: your company's, yours, or the project's.
In either case, just import the relevant header where you need to use the function or method, and you should be hunky-dory.
I'd consider writing a category on NSDate. Categories let you extend the functionality of existing classes with additional methods without having to mess with the existing implementation of the class. So you can add yourMethod to NSDate, and in the future just be able to call [yourDate yourMethod].
To do this in Xcode, just hit ⌘N to create a new file, and choose Objective-C category, then give it some name and make it a category on NSDate.
Then set up your header:
#interface NSDate (YourCategory)
- (NSString *) yourMethod;
#end
And your implementation:
#implementation NSDate (YourCategory)
- (NSString *) yourMethod {
return [NSString stringWithFormat:#"yourMethod on this date: ", [self description]]; // for example
}
#end
Then just include "NSDate+YourCategory.h" in any file where you want to use yourMethod.
i'd recommend adding the method to a catagory and then adding the header to your projects pch file
#ifdef __OBJC__
#import "yourHeader.h"
#endif
if you google for NSDate+Helper that should give you an idea of the implementation.
Nik
It's probably good to put it in 1 class as a method, then have another class add this class to take advantage of it's method.
simple 1 or 2 methods NSObject subclasses won't make slightest differences in execution

What exactly is 'super' doing in my apps?

Ok, this is going to be a really embarrassing question, but I looked like mad in my beginner's books (especially those usually helpful indices) and behold, I did not find a down-to-earth explanation of what 'super' does in my applications.
I had a look at this here, but I'm afraid that's well beyond me. Can anyone offer a very simply explanation of what 'super' does in my apps and why I should become friends with it? E.g.:
- (void)viewDidLoad {
[super viewDidLoad];}
Thanks!!
super calls the superclass's implementation of the method. So if your class inherits UIViewController, then [super viewDidLoad]; will call the UITableViewController class's viewDidLoad method. You should usually do this because the super class may do important things that need to happen. In the case of viewDidLoad, I'm not sure it actually does anything currently, but it always could in a future version of the framework.
at the low level, self contains a pointer to the set methods it responds to. this is a basic mechanism for the implementation of dynamic dispatch. each class is given a unique set. if you're familiar with c++, this is similar in concept to a virtual table. you can think of an objc method as being like a C function with 2 hidden arguments (self,_cmd).
super is a dynamically created representation of self, with a pointer to the next-in-line methods implemented by the instance's superclasses. this representation is based on self, and just directs to another set of implemented methods.
#interface MONTypeA : NSObject
- (void)monMethod;
#end
#interface MONTypeB : MONTypeA
- (void)monMethod;
#end
#implementation MONTypeA
- (void)monMethod {
printf("i am MonTypeA\n");
}
#end
#implementation MONTypeB
- (void)monMethod {
[super monMethod]; /* << will call -[MONTypeA monMethod], which will print "i am MonTypeA\n" */
printf("i am MonTypeB\n");
}
#end
if you create an instance of MONTypeA, then it will respond to monMethod:
MONTypeA * a = [MONTypeA new];
[a monMethod];
[a release], a = 0;
// outputs: "i am MonTypeA\n"
MONTypeB * b = [MONTypeB new];
[b monMethod];
[b release], b = 0;
// outputs: "i am MonTypeA\n""i am MonTypeB\n" because -[MONTypeB monMethod] calls through super
therefore, calling super performs the implementation of the method of the superclass in this specific case.
it is important to remember: the set of methods super refers to is always those of the previous implementation of the method in the hierarchy, it is not the same set as the set of instance methods which an instance of the superclass would be given (unless your class were to override every method).

Setting a delegate using blocks in iPhone

On a view controller I have multiple textfields, which all use the same delegate. Now in the delegate the code gets really ugly since I have to differentiate between all the textfields (bunch of if/else-if or a switch statement). I came a cross this article:
Blocks in textfield delegates
But from this I still don't understand how this solves the problem? Doesn't this basically call one method and pass it the text and the method has no idea what textfield gave the string? You would still need to differentiate between the textfields, but this time inside the block (with the usual if(textfield == bazTextField)...).
I don't know that it exactly solves the problem so much as shifts it (and into viewDidLoad, which usually gets a bit of mush-mash in it anyway).
However in that example the block itself was being passed in the textfield to run comparisons with and "remembers" the values of all the instance variables as well (if it refers to them), so that's how it knows what text and text field is being dealt with.
I don't see how that code exactly is supposed to help though, since it assigns one block to the single delegate class to be used with all text field delegates - unless perhaps you were supposed to have one per text field, each with a different block. Then you have way more code than you'd have had with the if statements!
The article doesn't make it clear, but I believe the idea is to create one of these blocks (and block delegate objects) for each UITextField that you wish to have respond to textFieldShouldReturn.
hm, maybe I didn't completely understand the article, but I don't see the advantage of using blocks instead of selectors in that concrete example.
you could achieve something similar like this
#interface AlternativeTextFieldDelegate : NSObject <UITextFieldDelegate>
{
SEL selectorToCall;
id objectToCall;
}
- (void) setObjectToCall:(id)obj selector:(SEL)selector;
#end
#implementation AlternativeTextFieldDelegate
- (void) setObjectToCall:(id)obj selector:(SEL)selector
{
objectToCall = obj;
selectorToCall = selector;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[objectToCall performSelector:selectorToCall];
return YES;
}
#end
and the view controller
#interface ViewWithTextFieldsController : UIViewController
{
UITextField *tf1;
AlternativeTextFieldDelegate *delegateForTF1;
UITextField *tf2;
AlternativeTextFieldDelegate *delegateForTF2;
}
// ...IBOutlets and all that...
- (void) tf1ShouldReturn; // handles shouldReturn for tf1
- (void) tf2ShouldReturn; // handles shouldReturn for tf2
#end
#implementation ViewWithTextFieldsController
- (void) viewDidLoad // or wherever
{
delegateForTF1 = [[AlternativeTextFieldDelegate alloc] init];
[delegateForTF1 setObjectToCall:self selector:#selector(tf1ShouldReturn)];
tf1.delegate = delegateForTF1;
delegateForTF2 = [[AlternativeTextFieldDelegate alloc] init];
[delegateForTF2 setObjectToCall:self selector:#selector(tf2ShouldReturn)];
tf2.delegate = delegateForTF2;
}
// ...
#end
don't really know if that's any better than chaining if-elses though.
it seems to me that this complicates things more than the problem it solves.