calling custom delegates not working - objective-c

I have made a custom delegate:
Example.h:
#protocol DismissExamplePopoverDelegate
- (void) dismissExamplePopover;
- (int) getUserID;
#end
#interface Example : UIViewController{
id<DismissExamplePopoverDelegate> delegate;
}
#property (nonatomic, assign) id<DismissExamplePopoverDelegate> delegate;
It is called in Example.m like follows:
[[self delegate] getUserID];
In my maincontroller.h:
#import "Example.h"
#interface MainScreen : UIViewController<DismissExamplePopoverDelegate>
maincontroller.m:
-(int) getUserID
{
return 100;
}
the view Example is called by the following method:
ExampleController = [[Example alloc] initWithNibName:#"Example" bundle:nil];
ExamplePopoverController = [[UIPopoverController alloc] initWithContentViewController:ExampleController];
[ExampleController setDelegate:self];
ExamplePopoverController.popoverContentSize = CGSizeMake(600, 480);
if ([ExamplePopoverController isPopoverVisible]) {
[ExamplePopoverController dismissPopoverAnimated:YES];
} else {
CGRect popRect = CGRectMake((self.EditExampleSelectAddButtonProperty.frame.origin.x),
(self.EditExampleSelectAddButtonProperty.frame.origin.y),
(self.ExampleSelectAddButtonProperty.frame.size.width),
(self.ExampleSelectAddButtonProperty.frame.size.height));
[ExamplePopoverController presentPopoverFromRect:popRect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
If I place [[self delegate] getUserID] in any function other than viewdidload it works perfectly: returns 100; in viewdidload it returns 0.
What i want to achieve is a delegate to be called automatically when the popover loads. Is viewdidload the best place for it, or is there somewhere else

A couple of people have said this, but haven't been clear enough about the solution.
Instead of doing this:
ExampleController = [[Example alloc] initWithNibName:#"Example" bundle:nil];
ExamplePopoverController = [[UIPopoverController alloc] initWithContentViewController:ExampleController];
[ExampleController setDelegate:self];
Do this:
ExampleController = [[Example alloc] initWithNibName:#"Example" bundle:nil];
[ExampleController setDelegate:self];
ExamplePopoverController = [[UIPopoverController alloc] initWithContentViewController:ExampleController];
What's happening is that -[UIPopoverController initWithContentViewController:] uses its contentViewController's view, causing -[Example viewDidLoad] to be called. Since you haven't yet set the delegate at that point, the delegate is nil, and attempting to call any method on nil returns nil, 0, or 0.0.

Make sure you're actually assigning the delegate property to MainController. For instance, wherever you've initialized Example, you need to set the delegate property:
Example *example = [[Example alloc] init];
example.delegate = self; // Use this if you're initializing Example in MainController
If you're not initializing Example in MainController, instead of "self" use the MainController instance.

In Example.m you need to add line:
[self setDelegate:delegate];
Also, you need to #synthesize delegate;
Hope it help)

Related

How can I pas another object's function as a selector in IOS?

I've read selector as parameter in IOS post. However, I want to extend the question.
In my case, I'm creating an Objective-C (not Swift) Master/Detail application, and want to create DetailController object of type UIViewController with the following init function
In DetailViewController.h
#interfact DetailViewController : UIViewController
- (id)initWithNibName:(NSString *)nibName withSaveSelector:(SEL)saveSelector
#end
... and in DetailViewController.m
- (id)initWithNibName:(NSString *)nibName withSaveSelector:(SEL)saveSelector
{
self = [super initWithNibName:nibName bundle:nil];
if (self) {
UIBarButtonItem *done = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:saveSelector];
[[self navigationItem] setRightBarButtonItem:done animated:YES];
}
return self;
}
NOW, I want to just keep re-using above code to create different DetailViewControllers, and want to pass a saveSelector function that will get called when the user presses the "Done" button.
Now I have another view controller
#interface AnotherViewController : UIViewController
- (void)saveSelector:(id)sender;
#end
...and then in yet another object (i.e., NOT in AnotherViewController.m code), I use the above view controller, like so...
AnotherViewController *avc = [[AnotherViewController alloc] init];
DetailViewController *dvc = [[DetailViewController alloc] initWithNibName:#"AnotherViewController" withSaveSelector:#selector(???)];
What should I put in the ??? so I can pass AnotherViewController::saveSelector() function to DetailViewController?
I hope that makes sense.
Change your method as:
- (id)initWithNibName:(NSString *)nibName withSaveSelector:(SEL)saveSelector forTarget:(id)target
And call it like this:
DetailViewController *dvc = [[DetailViewController alloc] initWithNibName:#"AnotherViewController" withSaveSelector:#selector(saveSelector:) forTarget:avc];
In DetailViewController.m
- (id)initWithNibName:(NSString *)nibName withSaveSelector:(SEL)saveSelector forTarget:(id)target
{
self = [super initWithNibName:nibName bundle:nil];
if (self) {
UIBarButtonItem *done = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:target
action:saveSelector];
[[self navigationItem] setRightBarButtonItem:done animated:YES];
}
return self;
}

EXC_BAD_ACCESS in UIWebView delegate

I've got a problem - I'm getting EXC_BAD_ACCESS when trying to set UIWebView.delegate = self;
My code:
vkLogin.h -
#import UIKit/UIKit.h
#interface vkLogin : UIViewController <UIWebViewDelegate>
{
UIWebView *authBrowser;
UIActivityIndicatorView *activityIndicator;
}
#property (nonatomic, retain) UIWebView *authBrowser;
#property (nonatomic, retain) UIActivityIndicatorView *activityIndicator;
#end
vkLogin.m -
#import "vkLogin.h"
#import "bteamViewController.h"
#implementation vkLogin
#synthesize authBrowser;
- (void) viewDidLoad
{
[super viewDidLoad];
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
activityIndicator.center = CGPointMake(self.view.bounds.size.width / 2, self.view.bounds.size.height / 2);
activityIndicator.autoresizesSubviews = YES;
activityIndicator.hidesWhenStopped = YES;
[self.view addSubview: activityIndicator];
[activityIndicator startAnimating];
authBrowser = [[UIWebView alloc] initWithFrame:self.view.bounds];
authBrowser.delegate = self;
authBrowser.scalesPageToFit = YES;
[self.view addSubview:authBrowser];
NSString *authLink = #"http://api.vk.com/oauth/authorize?client_id=-&scope=audio&redirect_uri=http://api.vk.com/blank.html&display=touch&response_type=token";
NSURL *url = [NSURL URLWithString:authLink];
[authBrowser loadRequest:[NSURLRequest requestWithURL:url]];
}
- (void) webViewDidFinishLoad:(UIWebView *)authBrowser
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Lol" message:#"OLOLO" delegate:self cancelButtonTitle:#"Okay" otherButtonTitles:nil, nil];
[alert show];
}
#end
So, if i'm commeting delegate string - everything working fine, but I didn't recieve my webViewDidFinishLoad event.
What I'm doing wrong?
The error isn't in the code you have posted. Your zombie message is saying your reference to vkLogin is bad. So you need to look at whatever class creates and holds a reference to your vkLogin class.
That class should be doing something like a vkLogin *foo = [[vkLogin alloc] init];
Update:
Based on your comments it looks like you are creating a local variable for vkLogin. It would be most useful to see the code creates and uses vkLogin and how it's called. Barring that, here are a few guesses.
You are called the method which creates and adds vkLogin to a subView more than once. (Each time would create a new instance).
You have some sort of call back which can occur after vkLogin has been removed.
My guess is vkLogin should be a property in your class, not a local method variable.
in your .h you would add
#proprerty (strong, nonatomic) vkLogin *vk;
and in your .m file you could refer to it as self.vk so you'd create it and add it as a subview like:
self.vk = [[vkLogin alloc] init];
[self.view addSubview:self.vk];
On a side note, convention says we should start class names with a capital letter, so you'd name the class VkLogin which would make it easily distinguishable from a variable named vkLogin (but worry about that after you solve the problem)

Cannot set property of UIImageView subclass

I've subclassed UIImageView, it's called ACCascadeImageView.
#interface ACCascadeImageView : UIImageView{
BOOL isSpotlight;
}
#property (assign, nonatomic) BOOL isSpotlight;
-----
#implementation ACCascadeImageView
#synthesize isSpotlight;
I then create instances like so, and add a gesturerecognizer..
ACCascadeImageView *imageview =
[[ACCascadeImageView alloc] initWithFrame:imageframe];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
[imageview addGestureRecognizer:singleTap];
In the handleSingleTap method, I loop through my UIScollView subviews, and I try to do this for each one...
(imageview in this scope is [gestureRecognizer view])
[imageview setIsSpotlight:NO];
But I get this...
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[UIImageView setIsSpotlight:]: unrecognized selector sent to instance 0x6888be0'
Why has my ACCascadeImageView suddenly become UIImageView? I apologize if I'm doing something stupid, but I've subclassed UIImageView before just fine. I'm confused.
I should say that I've NSLog'd [imageview class] and I get, "ACCascadeImageView".
Here's the problem:
NSArray *cascadeImages = [PhotoCascade subviews];
for (ACCascadeImageView *v in cascadeImages){
NSLog(#"RESPONDS: %d", [v respondsToSelector:#selector(setIsSpotlight:)]);
[v setIsSpotlight:NO];
}
I get :
RESPONDS: 1
RESPONDS: 0
Then it dies.
You can't be sure [gestureRecognizer view] is your UIImageView. To check this try NSLog(#"view: %#", [gestureRecognizer.view class]);. My tests says it's just UIView.
If you're adding gesture recognizer to your image view the selector will be fired only when the user taps this view. So you could omit those checks at all.
By your results, and since you only test once per object, it seems the first object in the array is your custom subview, but the second is not. Maybe somehow one of the objects in cascadeImages isn't an ACCascadeImageView. Step through the array and perform introspection on each one, logging the results, to make sure the array only contains ACCascadeImageViews.
You're saying that your handleSingleTap is returning TRUE in response to respondsToSelector:#selector(setIsSpotlight:), but then when you try to use setIsSpotlight, it fails? That is a mystery.
For example, I've created this super simple example, and it works as you'd expect:
#import "ViewController.h"
#interface Test : UIImageView
#property (assign, nonatomic) BOOL isSpotlight;
#end
#implementation Test
#synthesize isSpotlight;
#end
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
Test *test = [[Test alloc] initWithFrame:self.view.frame];
[self.view addSubview:test];
test.userInteractionEnabled = YES;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
[test addGestureRecognizer:tap];
}
- (void)handleSingleTap:(UIGestureRecognizer *)sender
{
Test *imageview = (Test *)[sender view];
NSLog(#"%s %d", __FUNCTION__, [imageview respondsToSelector:#selector(setIsSpotlight:)]);
[imageview setIsSpotlight:NO];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#end
The problem has to be something simple, but with limited code snippets provided in your question, it's not obvious what the problem is. But the code you've provided above would not manifest the sort of problem you describe. There must be some rogue UIImageView in your app!

Can you use a singleton in a view controller in a tab bar controller just as you would anywhere?

Clarification: The view controller with singletons described below works fine by itself. When embedded into a UITabBarController however, it doesn't work.
Original Title: NSUnknownKeyException: Probably not the nib, could it be the singletons?
Here's yet another one of those "NSUnknownKeyException... this class is not key value coding-compliant for the key" questions which are abundant here. I've been through a lot of them! Here's the full complaint:
NSUnknownKeyException', reason: '[<UIProxyObject 0x683dfe0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key button1.'
It seems these exceptions always come down to problems with the nib having left over variables that were changed elsewhere and did not get cleaned out. So I've worked through all my nib, disconnecting, and re-connecting, checking to no avail. I then deleted the nib and rebuilt it from zero and I have still have the same problem :-( So I turn to the hive mind of SO once again.
Through a series of NSLogs and other tricks I know the problem is with GameViewController (if I get rid of it and replace it with an empty controller the app works fine). Here is the relevant part of GameViewController:
#interface GameViewController : UIViewController <UIAlertViewDelegate>
#end
#implementation GameViewController
- (id) init {
NSLog(#" GVC initializing");
self = [super initWithNibName:#"GameViewController"
bundle:nil];
if (self) {
UITabBarItem *tbi = [self tabBarItem];
[tbi setTitle:#"Play Game"];
}
return self;
}
- (id) initWithNibName:(NSString *)nibName bundle:(NSBundle *)Bundle {
return [self init];
}
- (void)loadView {
[super loadView];
NSLog(#"loadView is starting");
// Set up display of button and label singletons
NSMutableArray *keyArray;
NSMutableArray *valueArray;
keyArray = [NSMutableArray arrayWithObjects:#"answerButtons", #"clueLabels", #"keyPad", nil];
valueArray = [NSMutableArray arrayWithObjects: [AnswerButtons answerButtons], [ClueLabels clueLabels], [KeyPad keyPad], nil];
NSMutableDictionary *externals = [NSMutableDictionary dictionaryWithObjects:valueArray
forKeys:keyArray];
// Fire the button and label singletons
[[AnswerButtons answerButtons] answerButtonsDidLoad];
[[ClueLabels clueLabels] clueLabelsDidLoad];
[[KeyPad keyPad] keyPadDidLoad];
// Set up nibOptions and link to externals
NSDictionary *nibOptions = [NSDictionary dictionaryWithObject:externals
forKey:UINibExternalObjects];
[self.nibBundle loadNibNamed:self.nibName owner:self options:nibOptions];
NSLog(#"loadView is done");
}
#end
Here is the relevant part of my app delegate:
#implementation AppDelegate
#synthesize window = _window;
#synthesize tbc = _tbc;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSLog(#"dFLWO starting");
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UITabBarController *tbc = [[UITabBarController alloc] init];
SettingsViewController *settingsVC = [[SettingsViewController alloc] init];
GameViewController *gameVC = [[GameViewController alloc] init];
// UIViewController *temp = [[UIViewController alloc] init]; // works fine
NSLog(#"dFLWO: both VC's inited");
[tbc setViewControllers:[NSArray arrayWithObjects:gameVC, settingsVC, nil]];
// [tbc setViewControllers:[NSArray arrayWithObjects: temp, settingsVC, nil]]; // works fine
NSLog(#"dFLWO: VC's set");
[[self window] setRootViewController:tbc];
[self.window makeKeyAndVisible];
NSLog(#"TabBarController now active");
return YES;
}
Sorry. That's long. I've gone as far as I can with this being a nib problem. Perhaps it is a problem with those singletons I need to launch? There was a previous version of this project without the tab bar controller in which these singletons (and others not shown) worked just fine.
Suggestions appreciated!

iAd notification *const__strong' to parameter of

I am introducing iAd on my app like previous but now, when adView.delegate = self, a notification is showed. Why? code seems to be like always with property and synthezise and also runs properly. Notification showed: "Passing 'ViewController *const__strong' to parameter of incompatible type 'id". Thank you.
- (void)viewDidLoad
{
//iAd
adView =[[ADBannerView alloc] initWithFrame:CGRectZero];
adView.requiredContentSizeIdentifiers = [NSSet setWithObjects: ADBannerContentSizeIdentifierPortrait, ADBannerContentSizeIdentifierLandscape, nil];
adView.delegate = self;
[self.view addSubview:adView];
[super viewDidLoad];
}
Verify that the ViewDelegate conforms to the protocol ADBannerViewDelegate:
#interface ViewController : UIViewController <ADBannerViewDelegate>
//...
#end