is there anyway to check if a specific instance of a class has already been created. I feel like it is hard to check if the instance already exists when there is a chance you may not have created it yet.
Here is my code:
-(IBAction)done:(id)sender
{ //I want to figure out how to check if 'newWindow' already exists before I create another 'newWindow'
SimpleTableView *newWindow = [self.storyboard instantiateViewControllerWithIdentifier:#"SimpleTableView"];
[self.navigationController pushViewController:newWindow animated:YES];
}
Thanks for all the help guys.
Yes, there is a simple way to do it.
You just need to have some reference to it (for example create a property) and check whether it is nil (not initialized) or not. You can do it like this:
if(!myReference){
//if you get here it means that it hasn't been initialized yet so you have to do it
}
First make newWindow an ivar or a property.
Then:
if (!newWindow){
newWindow = [self.storyboard instantiateViewControllerWithIdentifier:#"SimpleTableView"];
}
I wrote you a method that checks all viewControllers in UINavigationController:
- (BOOL)classExistsInNavigationController:(Class)class
{
for (UIViewController *controller in self.navigationController.viewControllers)
{
if ([controller isKindOfClass:class])
{
return YES;
}
}
return NO;
}
Use it like this:
- (IBAction)done:(id)sender
{
//I want to figure out how to check if 'newWindow' already exists before I create another newWindow
if (![self classExistsInNavigationController:[SimpleTableView class]])
{
SimpleTableView *newWindow = [self.storyboard instantiateViewControllerWithIdentifier:#"SimpleTableView"];
[self.navigationController pushViewController:newWindow animated:YES];
}
}
You can also do something like this:
- (UIViewController *)classExistsInNavigationController:(Class)class
{
for (UIViewController *controller in self.navigationController.viewControllers)
{
if ([controller isKindOfClass:class])
{
return controller;
}
}
return nil;
}
And use it like this if you want to pop to the viewController that exists already:
- (IBAction)done:(id)sender
{
//I want to figure out how to check if 'newWindow' already exists before I create another newWindow
UIViewController *controller = [self classExistsInNavigationController:[SimpleTableView class]];
if (!controller)
{
SimpleTableView *newWindow = [self.storyboard instantiateViewControllerWithIdentifier:#"SimpleTableView"];
[self.navigationController pushViewController:newWindow animated:YES];
}
else
{
[self.navigationController popToViewController:controller animated:YES];
}
}
You can use if/else to check newWindow exists or not.
if (newWindow) { // newWindow is exist to do something
// Do something.
} else { // newWindow is not exist to do something
// Do something.
}
You can implement an instance counter (https://stackoverflow.com/a/30509753/4647396) in the class you want to track.
Then just check if the counter is greater than 0.
If I interpret your question correctly you just want to know wether an instance exists and dont need a reference to it.
Related
I am using below code to check view controllers.
NSLog(#"addProductClicked 1===%#", self.class);
NSLog(#"addProductClicked 2===%#", [CategoriesViewController class]);
if ([self.class isKindOfClass:[CategoriesViewController class]]) {
NSLog(#"you go it right");
} else {
NSLog(#"you go it wrong");
}
The output I get is as below.
addProductClicked 1===CategoriesViewController
addProductClicked 2===CategoriesViewController
you go it wrong
Any idea what is going wrong?
Just to update, below is what I have defined my view controller...
#interface CategoriesViewController : GlobalViewController {
Now in GlobalViewController I have method where I am checking above...
The variable you want to class check should be passed in as an object, not as a class.
if ([self isKindOfClass:[CategoriesViewController class]]) {
NSLog(#"you go it right");
} else {
NSLog(#"you go it wrong");
}
Thats is wrong comparison. You call isKindOfClass: on the object of that class. Something like this:
CategoriesViewController *obj = [[CategoriesViewController alloc] init];
[obj isKindOfClass:CategoriesViewController];
In your case you probably want to put a check on self.
I'm checking if toViewController, which is the 2nd Tab in my tabBar, is of the class MatchCenterViewController, but the else statement is running instead, which tells me that it's not of that class.
I'm positive that the UIViewController in that tab is connected to MatchCenterViewController, so what else could cause this if statement to not work?
NSLog(#"numberOfMatches is 1");
UIViewController *toViewController = [self.tabBarController viewControllers][1];
NSLog(#"toViewController: %#", toViewController);
if ([toViewController isKindOfClass:[MatchCenterViewController class]]) {
NSLog(#"2nd matchcenter if statement works");
MatchCenterViewController *matchViewController = (MatchCenterViewController *)toViewController;
matchViewController.didAddNewItem = YES;
NSLog(#"alright they're set, time to switch");
}
else {
NSLog(#"toViewController is not MatchCenterViewController");
}
[self.tabBarController setSelectedIndex:1];
You can add NSLog(#"toViewController is of class: %#", NSStringFromClass([toViewController class]); and see the actual view controller class.
Or if didAddNewItem is a property that only MatchCenterViewController has, you can try this way:
if ([toViewController respondsToSelector:#selector(setDidAddNewItem:)]) {
// this is MatchCenterViewController
} else {
// this is not MatchCenterViewController
}
I've just implemented a commenting feature in my app. Ideally when someone leaves a comment, I'd like all notified people be able to swipe the push notification and open the app on that post.
I assume you want to open the concerned page directly. There are many ways to go about this, and it depends on how your app is laid out.
If you want to open an inner page upon app launch, you can programmatically trigger the segues that the user would otherwise need to make manually. (this ensures the back/home buttons work as opposed to loading the desired page directly).
Here's an excerpt from one of my own code, your use case may not be the same, but this is all i can do unless you give us more details.
- (BOOL) navigateToRespectiveSectionforPushNot:(NSDictionary*)pushNot
{
id rootVC = self.window.rootViewController;
NSLog(#"ROOT CLASS : %#", [rootVC class]);
if ([rootVC isKindOfClass:[SWRevealViewController class]])
{
NSLog(#"Root Class looking good... mission Navigate!!");
SWRevealViewController *homeVC = (SWRevealViewController*) rootVC;
NSString *category = [[pushNot objectForKey:pushPayloadKeyaps] objectForKey:pushPayloadKeyCategory];
NSString *subCat = [[pushNot objectForKey:pushPayloadKeyaps] objectForKey:pushPayloadKeySubCategory];
NSLog(#"category : %# , subcat : %#",category,subCat);
//The code for the page to which i'm supposed to navigate to is contained in the push notification payload
if ([category isEqualToString:pushCategoryItemChat])
{
[homeVC.rearViewController performSegueWithIdentifier:#"chatPush" sender:nil];
UINavigationController *nc = (UINavigationController*)homeVC.frontViewController;
NSLog(#"FrontView Class : %#",[nc.viewControllers[0] class]);
UITableViewController *tvc = (UITableViewController*)nc.viewControllers[0];
NSDictionary *send = #{chatPushTargetUserId:subCat,chatPushTargetUserName:#"",chatPushTargetUserImage:#""};
[tvc performSegueWithIdentifier:#"seguePushDemoVC" sender:send];
return YES;
}
//communityPush historyPush
else if ([category isEqualToString:pushCategoryItemCommunity])
{
if ([subCat isEqualToString:pushSubCatItemNewRequest])
{
[homeVC.rearViewController performSegueWithIdentifier:#"communityPush" sender:nil];
return YES;
}
else if ([subCat isEqualToString:pushSubCatItemAccepted])
{
[homeVC.rearViewController performSegueWithIdentifier:#"communityPush" sender:nil];
return YES;
}
}
else if ([category isEqualToString:pushCategoryItemHistory])
{
[homeVC.rearViewController performSegueWithIdentifier:#"historyPush" sender:nil];
return YES;
}
}
else
{
UIAlertView *whoa = [[UIAlertView alloc] initWithTitle:#"WHOA!!" message:#" That wasn't supposed to happen. You are not even logged in. Call 911..." delegate:nil cancelButtonTitle:#"mmKay.." otherButtonTitles:nil, nil];
[whoa show];
}
return NO;
}
I hope the code is self explanatory. cheers
Let's say that I have view controller Origin and Destination. I would like to declare something like:
//origin.m file
-(void)pushNextView {
self.conditional = YES;
[self performSegueWithIdentifier:#"toDestination" sender:self];
}
Where I have set my conditional as:
//origin .h file
#propery BOOL conditional;
Now in my Destination view controller I'd like to set a conditional based on the property that I've set in my origin:
// destination .m file
#import "OriginViewController.h"
OriginViewController *origin = [OriginViewController alloc] init];
if (origin.conditional == YES){
self.navigationItem.hidesbackbutton = YES;
}else{
// Do Nothing
}
for some reason this conditional statement does not work. Does this have to do anything with storyboards?
With the setup you seem to have it would be most easy to do this. You could directly access destination.hidesbackbutton when executing the segue:
//in origin.m
-(void) prepareForSegue.... {
if ([segue.identifier isEqualToString: #"identifierString"]) {
DestinationVC *destination = (DestinationVC*)[segue destinationViewController];
destination.hidesbackbutton = self.conditional; //you can set the .hidesbackbutton property here directly, no need for another property, if your setup is just as simple as in the given example
}
}
Like this, the destination doesn't check the origin's state and then set it's state, instead the origin just sets the destination's state.
You can do it both ways, but this way is more common.
Of course hidesbackbutton has to be a public property declared in DestinationVC .h file.
And as already mentioned, it should really be hidesBackbutton Or hidesBackButton.
(This all assumes that the class of your DestinationViewController is called DestinationVC)
Two things: hidesbackbutton looks like there's some camelCase missing. This should at least give a warning, doesn't it?
Also from an architectural point of view, I would not ask for the condition. Pass the state to the destination view controller and implement a BOOL variable there.
Draft:
// origin.m
- (void)prepareForSegue...
{
if([segue.identifier isEqualToString:"yourIdentifier"]) {
[(XYZViewController *)segue.destinationViewController setConditional:YES];
}
}
you should pass the state from your main controller to destination controller where you should handle this View state like and you have to define
//destination.h file
#propery BOOL conditional;
so when you push the controller from main you can set the destination controller view state in
- (void)viewDidLoad
{
[super viewDidLoad];
if (origin.conditional == YES) {
self.navigationItem.hidesBackButton = YES;
} else {
}
}
I have a workflow setup as follows:
Navigation Controller
-VC1
-VC2
-VC3
-PageVC
--VC4
--VC5
I pass an object for example a UIImage reference through the first controllers up to the PageVC. Once here the PageVC loads the controllers as follows:
- (void) viewDidLoad {
[super viewDidLoad];
self.dataSource = self;
_side = [self.storyboard instantiateViewControllerWithIdentifier: #"GuessGameTurnWordVC"];
_center = [self.storyboard instantiateViewControllerWithIdentifier: #"GuessGameTurnMainVC"];
[self setViewControllers: #[_center]
direction: UIPageViewControllerNavigationDirectionForward
animated: NO
completion: nil];
}
- (UIViewController*) pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
if ( viewController == _center )
{
_side.title = #"right";
return _side;
}
if ( viewController == _side && [_side.title isEqualToString: #"left"] )
{
return _center;
}
return nil;
}
- (UIViewController*) pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
if ( viewController == _center )
{
_side.title = #"left";
return _side;
}
if ( viewController == _side && [_side.title isEqualToString: #"right"] )
{
return _center;
}
return nil;
}
Question
Within the VC4/VC5 I need to access a property from the PageVC. How can I do this?
Do I need to pass the property down to these controllers too, or can I access it directly from its parent in someway?
Use the Singleton design pattern, write in your PageVC.m:
static NSObject yourObject;
#implementation PageVC
+(NSObject*)getThisObject{
if(!yourObject){
yourObject = [[NSObject alloc] init];
// init your object how you need it
}
return yourObject;
}
#end
and write in the PageVC.h:
+(NSObject*) getThisObject;
Now you can get this property in any class with this line:
NSObject *obj = [PageVC getThisObject];
But remember to include the PageVC.h in the other VCs.
I hope this was useful
You can access directly from it's parents. for parent's you meant they are subclasses of PageVC? Then just access it using VC4.propertyName if by parent's you meant viewController hierarchy within the NavigationController then you have different options.
The easiest one might be to create a property within your VC4 and VC5 then when you instantiate them just pass the value you want to use.
_side = [self.storyboard instantiateViewControllerWithIdentifier: #"GuessGameTurnWordVC"];
_side.someValue = something;
If you are going to use a variable or value over all your VC then I would suggest a singleton. Hope this helps