EXC_BAD_ACCESS in UIWebView delegate - objective-c

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)

Related

How to set/get UIImageView.image through Singleton?

I have two ViewControllers.
FirstViewController has UILabels and UIImageViews. Also generated a Singleton from its class.
SecondViewController has a call of that Singleton and should GET values of UILabels and UIImageViews from FirstViewController.
NSString works, UILabel do not.
For example, access a NSString in SecondviewController with "sharedFirstViewController.nsstringvarname" I can GET and SET the value.
This works fine!
Trying the same with an UILabel like this: "sharedFirstViewController.uilabelvar.text" I doens´t can SET or GET the value of this UILable.
This works NOT!
Is there any special thing with UI-Objects?
Would be great if someone can help me with that.
Thanks!
EDIT:
in FirstViewController.h
+ (id)sharedFirstViewController;
#property (copy, nonatomic) NSString *path;
#property (strong, nonatomic) IBOutlet UIImageView *pic;
in FirstViewController.m
#synthesize path= _path;
#synthesize pic = _pic;
- (id)init {
if (self = [super init]) {
_pic = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 200)];
}
return self;
}
+ (id) sharedFirstViewController {
static sharedFirstViewController * sharedFirstViewController = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedFirstViewController = [[self alloc] init];
});
return sharedFirstViewController;
}
in SecondViewController.m
#import "FirstViewController.h"
- (void)viewDidLoad
{
FirstViewController * sharedFirstViewController = [FirstViewController sharedFirstViewController];
NSLog(#"this is NSString from FVC: %#" sharedFirstViewController.path); //works
UIImage * picture = [UIImage imageWithContentsOfFile:sharedFirstViewController.path];
sharedFirstViewController.pic.image = picture; // does´t work
}
I'm sure you forget to give allocation to UIImageview *pic in init method of singleton class. That because your code running but without any crash and warning. If you debug your code you will get imageview memory allocation 0X0. check it.
- (id)init {
if (self = [super init]) {
_pic = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 200)];
}
return self;
}
write above method in in FirstViewController.m class. Their is doesn't need of write IBOutlet in front of UIImageView *pic because you not mention your viewcontroller nib while generation singleton instance. Use IBOutlet whenever you dealing UI in xib.

calling custom delegates not working

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)

How can I reuse a UIView and methods - DRY code in iOS

I have 2 methods that add the Previous, Next & Done toolbar above the iOS Keyboard and handle these actions. I'm looking for a way to code these methods once and reuse it across multiple UITableViewControllers. (DRY Code)
I find myself copy and pasting these methods into each UITableViewController. If I make a small change, I have to copy and pastes that change everywhere. The code below is just an example, I seem to be repeating myself a lot in my code.
Here's an example of the code I'd like to reuse:
- (void) createInputAccessoryView
{
_inputAccView = [[UIView alloc] initWithFrame:CGRectMake(10,0,310,42)];
UIToolbar *keyboardToolbar = [[UIToolbar alloc] init];
keyboardToolbar.barStyle = UIBarStyleBlackTranslucent;
[keyboardToolbar sizeToFit];
_segmentedControl = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"Previous", #"Next", nil]];
[_segmentedControl setSegmentedControlStyle:UISegmentedControlStyleBar];
[_segmentedControl addTarget:self action:#selector(nextPrevious:) forControlEvents:UIControlEventValueChanged];
UIBarButtonItem *nextPrevButton = [[UIBarButtonItem alloc] initWithCustomView:_segmentedControl];
UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
UIBarButtonItem *doneBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(resignKeyboard)];
NSArray *barItems = [NSArray arrayWithObjects:nextPrevButton, flexSpace, doneBtn, nil];
[keyboardToolbar setItems:barItems];
[_inputAccView addSubview:keyboardToolbar];
}
- (void) nextPrevious:(id) sender
{
switch(_activeTxtField.tag) {
case 1:
//Recipe Name
if (_segmentedControl.selectedSegmentIndex == 1){
[_descriptionTextField becomeFirstResponder];
_activeTxtField = _descriptionTextField;
}
break;
case 2:
//Recipe Description
if (_segmentedControl.selectedSegmentIndex == 0){
[_nameTextField becomeFirstResponder];
_activeTxtField = _nameTextField;
}
default:
break;
}
}
Create a custom UIView that defines the common input accessory view. Should include a definition of a delegate to allow the class using the accessory view to handle, for example, previous/next button taps as appropriate. Here's a header file example for a keyboard accessory view:
#import <UIKit/UIKit.h>
#class KeyboardAccessoryView;
#protocol KeyboardAccessoryViewDelegate <NSObject>
-(void)accessoryNext:(id)sender;
-(void)accessoryPrevious:(id)sender;
#end
#interface InputAccessoryView : UIView
#property (nonatomic, weak) id<KeyboardAccessoryViewDelegate> delegate;
#property (nonatomic, setter = enablePrevious:) BOOL previousEnabled;
#property (nonatomic, setter = enableNext:) BOOL nextEnabled;
-(id)initPreviousNextAccessory;
#end
Edit - showing details of use in a UIViewController.
The .h file:
#import <UIKit/UIKit.h>
#import "KeyboardAccessoryView.h"
#interface MyViewController : UIViewController <KeyboardAccessoryViewDelegate>
//...
#end
The .m file:
#import "MyViewController.h"
#interface MyViewController () {
KeyboardAccessoryView *inputAccessoryView;
}
#end
#implementation MyViewController
//...
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
inputAccessoryView = [[KeyboardAccessoryView alloc] initPreviousNextAccessory];
inputAccessoryView.delegate = self;
//...
}
-(void)accessoryNext:(id)sender{
// handle Next
}
-(void)accessoryPrevious:(id)sender{
// handle Previous
}
//...
#end

iOS Passing (Retain) the value of an NSMutableArray to another NSMutableArray in another view

I'm using .XIB and without ARC. I'm passing the value of the NSMultableArray to another view, if I put [self presentModel...], it works, but if I call the AnotherView with a button the value of the NSMultableArray of the AnotherView is null!
AnotherView.h
#interface AnotherViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>{
NSMutableArray *otherAnother;
NSMutableArray *arrayOfTheAnotherView;
}
#property (retain, nonatomic) IBOutlet UITableView *tableView;
#property (retain, nonatomic) NSMutableArray *arrayOfTheAnotherView;
AnotherView.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
otherAnother = [[NSMutableArray alloc]init];
otherAnother = [[NSMutableArray alloc]initWithArray:self.arrayOfTheAnotherView];
//    [otherAnother addObjectsFromArray:arrayOfTheAnotherView];
NSLog(#"%#", self.arrayOfTheAnotherView);
}
The NSLog has written "null"
CurrentView.h
#interface CurrentViewController : UIViewController {
NSMutableArray * arrayCurrentView;
AnotherViewController *superAnotherView;
}
#property (retain, nonatomic) AnotherViewController *superAnotherView;
CurrentView.m
#synthesize superAnotherView;
NSString *x = [[NSString alloc]initWithFormat:#"%#",[label text]];
arrayCurrentView = [[NSMutableArray alloc]init];
[arrayCurrentView retain];
[arrayCurrentView addObject:x];
self.superAnotherView = [[AnotherViewController alloc]initWithNibName:nil bundle:nil];
self.superAnotherView.arrayOfTheAnotherView = [[NSMutableArray alloc]init];
[self.superAnotherView.arrayOfTheAnotherView retain];
[self.superAnotherView.arrayOfTheAnotherView addObjectsFromArray:arrayCurrentView];
I don't know how to retain the value of the NSMultableArray, thanks the help.
It is how I call the AnotherView:
UIButton *buttonAnother = [UIButton buttonWithType:UIButtonTypeCustom]; [buttonAnother setTag:5]; [buttonAnother addTarget:self action:#selector(switchTabBar:) forControlEvents:UIControlEventTouchDown];
[tabBarViewController.view addSubview:buttonAnother];
- (IBAction)switchTabBar:(id)sender { switch ([(UIButton *)sender tag]) { case 5: [self.tabBarController setSelectedIndex:0]; break; }
These should not be necessary:
self.superAnotherView.arrayOfTheAnotherView = [[NSMutableArray alloc]init];
[self.superAnotherView.arrayOfTheAnotherView retain];
Properties are already initialized when the class is initialized.
In fact, your explicit retain lines shouldn't be necessary at all; you're not releasing them as far as I can see and just making the retain count 2 so that it has to be released twice.
I think there's something going on here that the methods and view controllers are not being called in the order you want, probably something to do with the tab bar.
I dicoverd! I'm using the MVC
A array of the APP delegate don't lost its value.
AppDelegate
NSMutableArray *arrayDelegate;
View.m
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
[appDelegate.arrayDelegatePedido addObject:#"title"]; //for example

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!