I've searched this issue for a solid amount of time, and I couldn't find an answer that solved my problem. If there are any similar questions that I missed and that have a working solution, please post a link to them.
Anyways...
I have a menu filled with buttons that, when clicked, opens up a UIWebView which opens a specific webpage. Everything works fine, but only after the second try. To be a little more clear, the first time I tap a button, the webpage gets stuck loading, but after you close it out and tap it again, the pages load up just fine.
Since I'm using multiple buttons, I decided to put them all in an IBOutlet Collection:
#property (nonatomic, retain) IBOutletCollection(UIButton) NSArray *btnArray;
I then set up an array that would hold all the buttons from the collection, set up a view controller for our webview class (we have a separate class for webviews, which has not caused me any problems in the past) and the webview's navigation controller, and finally I used a for loop to add all the buttons the array.
NSMutableArray *theButtons = [[NSMutableArray alloc] init];
webVC = [[WebviewViewController alloc] init];
webNav = [[UINavigationController alloc] initWithRootViewController:webVC];
for(int i = 0; i < [btnArray count]; i++)
{
UIButton *btn = btnArray[i];
btn.tag = i;
[theButtons addObject:btn];
[theButtons[i] addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
}
I also have set up an array with the end links of all the pages I need to go to, which will be appended to a url:
pages = #[#"exOne.php", #"exTwo.php", #"exThree.php", #"exFour.php", #"exFive.php", #"exSix.php"];
Note: all the above code in -viewDidLoad
Here is the method that handles what happens when a button is clicked:
-(void)buttonPressed : (id) sender
{
UIButton *clicked = (UIButton *) sender;
NSMutableString *url = [NSMutableString stringWithString:#"http://www.example.org/examples/"];
for(int i = 0; i < [btnArray count]; i++)
{
if(i == clicked.tag)
{
[url appendString:pages[i]];
[webVC loadURL:url];
webNav.navigationBar.translucent = NO;
webNav.navigationBar.topItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStyleBordered target:self action:#selector(backPressed)];
[self.navigationController pushViewController:webVC animated:YES];
}
}
}
If it wasn't clear from the method call
[webVC loadURL:url];
just sends the link to our webviewViewController class and loads the link.
Any ideas on why the webpages only load after the second attempt?
Your WebviewViewController has probably not been loaded when you call loadURL the first time. If the view controller is not loaded it's subviews and hence it's embedded UIWebView are not available. When you push the controller it gets loaded and the second time loadURL will work.
Related
I have programmatically generated UIButtons that all share the same selector method. When the method runs I would like the method to know which button was pressed and then be able to load a corresponding UIViewController.
-(void)buildButtons
{
for( int i = 0; i < 5; i++ ) {
UIButton* aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[aButton setTag:i];
[aButton addTarget:self action:#selector(buttonClicked:)forControlEvents:UIControlEventTouchUpInside];
[aView addSubview:aButton];
}
Then:
- (void)buttonClicked:(UIButton*)button
{
NSLog(#"Button %ld clicked.", (long int)[button tag]);
// code here that picks the correct viewController to push to...
// for example tag 1 would create an instance of vcTwo.m and would then be pushed to the navigationController and be displayed on screen
}
say I have three UIViewController classes (vcOne.m, vcTwo.m, vcThree.m) and I want it so that when the button is pressed 'buttonClicked' is run and the code picks the corresponding viewController to push to. I don't want to use a series of if statements as there may be dozens/hundreds of viewControllers in the end. Would I have to instantiate all of the viewControllers and put them in an array? Is there a better way?
Are you using storyboards? so you can chose a segue according to the button tag:
int i = (int)[button tag];
[self performSegueWithIdentifier:[NSString stringWithFormat:#"Segue%d", i] sender:self];
or:
UIViewController *viewController= [controller.storyboard instantiateViewControllerWithIdentifier:NSString stringWithFormat:#"ViewControllerNumber%d", i];
In the end I went with this:
- (void) buttonClicked:(id)sender
{
NSLog(#"Button tag = %li", (long)[sender tag]);
FormularyVC *formularyVCInstance = [FormularyVC alloc];
ProceduresVC *proceduresVCInstance = [ProceduresVC alloc];
VetMedVC *vetMedVCInstance = [VetMedVC alloc];
NSArray *vcArray = [NSArray arrayWithObjects:formularyVCInstance, proceduresVCInstance, vetMedVCInstance, nil];
UIViewController *vcToLoad = [vcArray objectAtIndex:(int)[sender tag]];
vcToLoad.view.backgroundColor = [UIColor whiteColor];
[self.navigationController pushViewController:vcToLoad animated:NO];
}
I created an array of the ViewControllers I wanted to be able to load based on which button was pressed. When the button is pressed the method is run and the tag is taken as a parameter. This tag is used to find the ViewController needed by checking its location on the array's index.
I guess I'm missing something obvious, but I simply can't figure out how to obtain the label of a CCMenuItemFont.
Background
I'm building a simple hangman game for the iPad. For entering the next guess, I've added 26 buttons to the UI (one for each letter of the alphabet) and wired them all to the same event handler.
Now, inside the event handler, I'd like to obtain the label of the button to update the current guess, but CCMenuItemFont apparently doesn't respond to text or label.
Problem
So - what method can I use to obtain the label of a CCMenuItem?
Code
Code for creating the buttons:
-(void)addButtons {
NSArray* charArray = [NSArray arrayWithObjects:
#"A",#"B",#"C",#"D",#"E",#"F",#"G",#"H",#"I",#"J",#"K",
#"L",#"M",#"N",#"O",#"P",#"Q",#"R",
#"S",#"T",#"U",#"V",#"W",#"X",#"Y",#"Z", nil];
[CCMenuItemFont setFontName:#"Marker Felt"];
[CCMenuItemFont setFontSize:45];
NSMutableArray* buttonArray = [NSMutableArray array];
for (unsigned int i=0; i < [charArray count]; ++i) {
CCMenuItemLabel* buttonMenuItem = [CCMenuItemFont
itemWithString:(NSString*)[charArray objectAtIndex:i]
target:self selector:#selector(buttonTapped:)];
buttonMenuItem.color = ccBLACK;
buttonMenuItem.position = ccp(60 + (i/13)*40, 600 - (i%13)*40);
[buttonArray addObject:buttonMenuItem];
}
CCMenu *buttonMenu = [CCMenu menuWithArray:buttonArray];
buttonMenu.position = CGPointZero;
[self addChild:buttonMenu];
}
And the event handler:
- (void)buttonTapped:(id)sender {
// Get a reference to the button that was tapped
CCMenuItemFont *button = (CCMenuItemFont *)sender;
[_guess addObject:[button text]]; // this throws an exception because text is the wrong method
[self paintCurrentGuess];
}
You're adding to your menu a CCMenuItemLabel, not a CCMenuItemFont (which actually extends the first one). In both cases, you need to access to the inner label containing the text.-
CCMenuItemLabel *button = (CCMenuItemLabel *)sender;
NSString *label = button.label.string;
i have a Navigation Bar, wich contains a Navigation Item, which contains 2 Bar Buttons, these are created in the Storyboard, and i wanted to change 1 of the buttons at runtime, now this works:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
UINavigationItem *thisNavBar = [self myNavigationItem];
thisNavBar.rightBarButtonItem = nil; // this works, it gets removed
UIBarButtonItem *insertBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:#selector(insertSkemaItem:)];
thisNavBar.rightBarButtonItem = insertBtn; // this also works, it sets the btn
}
Now, in my other method, which is called by another controller, it does not work
- (void)callChildChange {
...
// remove old btn
UINavigationItem *thisNavBar = [self skemaNavigationItem];
thisNavBar.rightBarButtonItem = nil; // does not work?
}
There is nothing wrong with the method, it runs just fine, but the nav btn item does not get removed ?
skemaNavigationItem is a Navigation item, declared in the .h file which links the navigation item i made via the storyboard.
Your UI items need to be added to your code (by ctrl-dragging) in the header file (.h) so they can be publicly accessed from other classes/view controllers.
Presuming you've done this, hiding a UI item is best done by using
relevantClass.yourViewObject.hidden = YES;
or if you really need to delete it for good,
[relevantClass.yourViewObject.view removeFromSuperView];
Edits
Options for changing target method:
Declare #property (nonatomic, assign) BOOL myButtonWasPressed; and:
- (IBAction) myButtonPressed
{
if (!self.myButtonWasPressed)
{
// This code will run the first time the button is pressed
self.myButton.text = #"New Button Text";
self.myButtonWasPressed = YES;
}
else
{
// This code will run after the first time your button is pressed
// You can even set your BOOL property back, and make it toggleable
}
}
or
- (IBAction) myButtonWasPressedFirstTime
{
// do what you need to when button is pressed then...
self.myButton.text = #"New Button Text";
[self.myButton removeTarget:self action:#selector(myButtonPressedFirstTime) forControlEvents:UIControlEventTouchUpInside];
[self.myButton addTarget:self action:#selector(myButtonPressedAgain) forControlEvents: UIControlEventTouchUpInside];
}
- (IBAction) myButtonWasPressedAgain
{
// this code will run the subsequent times your button is pressed
}
I am creating buttons inside the for loop below shown is the code for that
for(int i=1;i<[_imageDetailsEntities count];i++)
{
UIButton *bttn=[UIButton buttonWithType:UIButtonTypeCustom];
bttn.frame=CGRectMake(x,y,75,75);
[_scrollView addSubview:bttn];
ImageDetails *imageDetails=[_imageDetailsEntities objectAtIndex:i];
UIImage *image= [self imageFromPath:imageDetails.imagePath];
[bttn setImage:image forState:UIControlStateNormal];
bttn.tag=i-1;
[bttn addTarget:self action:#selector(imageTapped:) forControlEvents:UIControlEventTouchUpInside];
x=bttn.frame.origin.x+bttn.frame.size.width+distanceBetweenButtons;
if(i%3==0)
{
x=29;
y=y+bttn.frame.size.height+20;
}
}
[_scrollView setContentSize:CGSizeMake(320,y+95)];
-(void)imageTapped:(id)sender
{
UIButton *bttn=(UIButton*)sender;
[_delegate didFinishChoosingImageAtIndex:bttn.tag];
}
App is crashing with EXC_Bad access message when i tap a button.I am using ARC. I am not sure, what i am missing here.Please help me
Try replacing following line under imageTapped:
[_delegate didFinishChoosingImageAtIndex:bttn.tag];
with
if([_delegate respondsToSelector:#selector(didFinishChoosingImageAtIndex:)]){
[_delegate didFinishChoosingImageAtIndex:bttn.tag];
}
Try turning on NSZombie and see if something is being released too soon.EXC_BAD_ACCESS means that something was already deallocated when you sent it the message.
Don't know what your code does exactly, but it looks like your for-loop has a one-off error.
Either use
for(int i=0;i<[_imageDetailsEntities count];i++)
or
for(int i=1;i<=[_imageDetailsEntities count];i++)
if you want to iterate over all thingies.
you should maintain an array of the buttons in your controller, so ARC doesnt dealloc them.
In your interface:
#property (nonatomic, strong) NSMutableArray *buttons;
Your code:
NSMutableArray *buttons = [NSMutableArray array];
for(int i=1;i<[_imageDetailsEntities count];i++)
{
...your code
[buttons addObject:bttn];
}
self.buttons = buttons;
You could use that array again to remove buttons from the view if need be.
Based on some earlier questions (ex: ios5 how to pass prepareForSegue: a UIImageView) I was wondering how smooth this technique is, say when doing a modal segue with animated = NO.
I can toss together a test but I imagine someone has already scoped out the performance and practical pitfalls of using this as a transition technique. I would be interested in hearing any details - for example, does the UIImageView animation restart or does it continue apace?
If you pass an animating image view to another controller, it looks like the animation continues apace. I can't see any "hitch" in the animation. Going forward with a modal presentation worked fine. I couldn't go back to the first controller, by just dismissing, I had to add the image view back to the view to make that work, and even then it only worked if I turned off auto layout (otherwise I get an error saying it can't install a constraint). So, to go back and forth with modals (with no animation) I had this in the first controller:
- (void)viewDidLoad {
[super viewDidLoad];
self.isFirst = YES;
NSMutableArray *imgArray = [NSMutableArray array];
for (int i = 1; i< 41; i++) {
UIImage *img = [UIImage imageNamed:[NSString stringWithFormat:#"New_PICT%04d.jpg",i]];
if (img) {
[imgArray addObject:img];
}
}
self.iv.animationImages = imgArray;
self.iv.animationDuration = 10;
[self.iv startAnimating];
}
-(void)viewDidAppear:(BOOL)animated {
if (self.isFirst) {
self.isFirst = NO;
}else{
self.iv.frame = CGRectMake(48, 48, 48, 48);
[self.view addSubview:self.iv];
}
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
SecondViewController *sec = segue.destinationViewController;
sec.iv = self.iv;
}