I am fairly new to ObjectiveC (+/- two weeks), so I'm having trouble to implement something that would be fairy easy in other languages, I hope someone can help (if it's possible):

Background: I have an interface with many windows in a fairly complex architecture, each window can call others (ViewControllers, TableViewControllers, Tab/Nav VC, etc). I am using "Modal" for now, as I can't figure how to use Push without bugs. Each window has somewhere a button that calls a dismissViewController, this button is the same everywhere (same graphics, position, etc).

I thought it's messy to create an IBAction for each one of them, give exactly the same name and the same function, so I decided to create a "Custom Class" of UIButton category, put all the parameters there, and just give the buttons in storyboard a class so they can be configured without a hassle.

Problem: While this works perfectly for some buttons having a complex function, it doesn't work with dismissViewController ... I suppose it's because I am using "self", which is wrong here, but I am unaware of how to use the "parent"? Here is the code

#import "returnToMainMenuButton.h"

@implementation returnToMainMenuButton

-(IBAction)returnToMainMenu:(id)sender
{
    [self dismissViewControllerAnimated:YES completion:nil];

}
@end

Question: 1) Is it possible to do this? As I don't really like repeating exactly the same steps 10 times in my code, I would rather call the action once rather than declare it and initiate it. (I suppose there is a possibility as we can select a predefined type like "Add", "Save", etc)

2) If yes, could you please show me how or a tutorial that does this?

3) If not, is there any other way to do something like this?

Thank you very much. Cheers

有帮助吗?

解决方案

The primary problem here is that UIButton knows of no method called dismissViewControllerAnimated:completion: This is a UIViewController method.

Further more, there is no way to start with a UIView (or subclass, which your class is a subclass of a subclass of) and get to its view controller. A UIViewController can get to all its views and subviews though. But there's no guarantee how deeply nested your UIButton is in the view hierarchy, we'd have to recurse through every view and find one that matches your button's class.

The only real option I can think of here is to create a UIViewController subclass with a method that looks like this:

- (IBAction)exit:(id)sender {
    if (self.navigationController) {
        [self.navigationController popViewControllerAnimated:YES];
    } else {
        [self dismissViewControllerAnimated:YES completion:nil];
    }
}

So now this code will get rid of the view controller whether or not it's in a navigation controller (as a note, the if check may not be good enough--may need some more conditions).

Now, make all of your view controllers a subclass of this view controller. And hook your regular, non-subclassed UIButtons up to a method that looks like this:

- (IBAction)exit:(id)sender {
    [super exit:sender];
}

If you need to do perform any additional code when pushing the button, you can put it around the call to super. You still have to hook up the button to every view controller... unless you want to give every button a reference to the view controller it needs to dismiss. But this way is less messy and easier to maintain. The view controllers need to be in charge of when they're dismissed or about to present a new view controller. The logic for changing view controllers shouldn't be outside view controller classes.

其他提示

For this thing, On button's action you can get parent view controller of the current view controller, now if it is UINavigationViewController then you can pop the view else you can dismiss it.

So, I actually solved more than half of the problem, while I still can't find the exact parent (or current view), I could do the setup quickly, which saves me a lot of time.

Basically, in the UIButton class (ButtonClass.m), I initiate the button in "initWithFrame" as follow:

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        // Styling goes here, such as title, image, and position/alignment
        // Adding an IB Action as follow:
        [self addTarget:self action:@selector(theAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.window.rootViewController dismissViewControllerAnimated:YES completion:nil];    
    }
    return self;
}

The action, on the same file:

-(IBAction)theAction:(id)sender
{
    //This works, but returns me to the root view
    [self.window.rootViewController dismissViewControllerAnimated:YES completion:nil];
    //This works really weirdly and is inconsistent [self.window.rootViewController.parentViewController dismissViewControllerAnimated:YES completion:nil];
}

From here, no need to use the Storyboard in anything, in any view I'd need the button, it's enough to just do this:

#import "ButtonClass.h"

then

UIButton *button = [[ButtonClass alloc] init];
[self.view addSubview:button];

I hope this helps anyone trying to reduce work by binding actions/styles to buttons (any action that is unrelated to the current view will work, such as accessing Core Data or Multipeer Connectivity, etc).

If there is anyway to pass the current view's self to the button upon creation, I'd be glad to know it. I know it should be possible, but not how to do that in objective-C. Thank you

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top