I am using SWRevealViewController to implement a side menue in my application. in storyboard i have set the sw_front segue. this segue is loading the MainView on every start of application. now i want to give the user the possibility to change the first displayed viewcontroller.
How can i do that? I know there is a property setFrontViewController: but where should i use this to load the front during application start?
I cant use it in the viewDidLoad of the frontViewController which i set in Storyboard. That could not be a solution, so i would need to do it in every view controller to grab and check the "should load another view controller as first or frontViewController"
I have understood what you have problem and what you want to do i have also the same kind of thing to do, so what i have done create the custom segue in the swrevealviewcontroller that i have also mention in my code.
and modified the two methods perform and loadstoryboardcontroller methods, you can also see in my code.
It will definetely work for you as well.
Have a happy coding cheers.
My code is below:
I have done this the code you need to change is below.
- (void)loadStoryboardControllers
{
if ( self.storyboard && _rearViewController == nil )
{
//Try each segue separately so it doesn't break prematurely if either Rear or Right views are not used.
#try
{
[self performSegueWithIdentifier:SWSegueRearIdentifier sender:nil];
}
#catch(NSException *exception) {}
#try
{
[self performSegueWithIdentifier:SWSegueFrontIdentifier sender:nil];
}
#catch(NSException *exception) {}
#try
{
[self performSegueWithIdentifier:SWSegueRightIdentifier sender:nil];
}
#catch(NSException *exception) {}
#try
{
[self performSegueWithIdentifier:SWSegueCustomIdentifier sender:nil];
}
#catch(NSException *exception) {}
}
}
#pragma mark - SWRevealViewControllerSegueSetController segue identifiers
NSString * const SWSegueRearIdentifier = #"sw_rear";
NSString * const SWSegueFrontIdentifier = #"sw_front";
NSString * const SWSegueRightIdentifier = #"sw_right";
NSString * const SWSegueCustomIdentifier = #"sw_custom";
#pragma mark - SWRevealViewControllerSegueSetController class
#implementation SWRevealViewControllerSegueSetController
- (void)perform
{
SWRevealControllerOperation operation = SWRevealControllerOperationNone;
NSString *identifier = self.identifier;
SWRevealViewController *rvc = self.sourceViewController;
UIViewController *dvc = self.destinationViewController;
if ( [identifier isEqualToString:SWSegueFrontIdentifier] )
operation = SWRevealControllerOperationReplaceFrontController;
else if ( [identifier isEqualToString:SWSegueRearIdentifier] )
operation = SWRevealControllerOperationReplaceRearController;
else if ( [identifier isEqualToString:SWSegueRightIdentifier] )
operation = SWRevealControllerOperationReplaceRightController;
else if ( [identifier isEqualToString:SWSegueCustomIdentifier])//your conditional segue
operation = SWRevealControllerOperationReplaceFrontController;
if ( operation != SWRevealControllerOperationNone )
[rvc _performTransitionOperation:operation withViewController:dvc animated:NO];
}
#jogshardik has the correct answer for my question but i found also another solution.
In your storyboard you are connecting a custom segue "sw_front" with your viewcontroller. This viewcontroller is on every initial start your first front viewcontroller. So you just have to check in this controller if you need to set another front viewcontroller.
i set up a notification in this "sw_front" viewcontroller and also in your Side Menue View Controller add the notification handler.
if you want to change the view just fire the notification and let do the notifaction handler the rest (set your setFrontViewController: property).
So this also works and is update stable if you need to keep attention on newer versions.
if this information is not enough for you, give me a hint and i will post an example code or project when i have time.
Related
So i am showing a model controller on top of a view controller. And i have texts in the model controller, but somehow the texts are not visible. I tried everything but somehow labels are not visible. But of you stay on the page for like 30 -40 sec the text shows up. Also this model controller is called from main view controller after a successful service(REST) call. If i call the model without making the service call then labels are visible in simulator/iPad both. But if i call it after service call inside success block then labels are not visible. I tried adding the text programmatically but still same issue. I tried debugging using Color blended layers, but the label is not at all visible in the view somehow. :(
[self.serviceManager getCustDetails:account successBlock:^(NSDictionary * successDict) {
[self hideLoadingAnimation];
NSDictionary *custData = [[successDict objectForKey:#"txnData"] objectForKey:#"custData"];
self.showCurrYear = [iraContribData objectForKey:#"showCurrYear"];
if ([self.showCurrYear isEqual: #"true"]){
[self performSegueWithIdentifier:#"CSegue" sender:self];
}
} failureBlock:^(NSDictionary * failureDict) {
[self hideLoadingAnimation];
NSLog(#"Failiure Dict %#",failureDict);
}];
And this prepareForSegue method, -
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"CSegue"]) {
CustViewController *cVC = segue.destinationViewController;
cVC.delegate = self;
[cVC setModalPresentationStyle:UIModalPresentationFormSheet];
cVC.preferredContentSize = CGSizeMake(800,750);
}
}
Below is my screen in storyboard, but in simulator the label is not visible, only continue and close button is visible.
Please help!, any suggestions are most welcome. Thanks!
It is possible that the delay is due to a user interface update not made on the main thread.
Try to make sure that your code is executed on the main thread using dispatch_async like this :
[self.serviceManager getCustDetails:account successBlock:^(NSDictionary * successDict) {
dispatch_async(dispatch_get_main_queue(), ^{
[self hideLoadingAnimation];
NSDictionary *custData = [[successDict objectForKey:#"txnData"] objectForKey:#"custData"];
self.showCurrYear = [iraContribData objectForKey:#"showCurrYear"];
if ([self.showCurrYear isEqualToString:#"true"]){
[self performSegueWithIdentifier:#"CSegue" sender:self];
}
});
} failureBlock:^(NSDictionary * failureDict) {
dispatch_async(dispatch_get_main_queue(), ^{
[self hideLoadingAnimation];
NSLog(#"Failiure Dict %#",failureDict);
});
}];
My Application is getting crashed with the following error.
-[PreviewViewController applicationWillSuspend]: message sent to deallocated instance 0x1806d9e0
My application have two view controllers one is HomeViewController and other one is PreviewViewController.
In home view controller i am displaying a table view. When selecting the row of table view i am presenting the preview view controller.
I selected one row then preview view controller is presented.
PreviewViewController *previewController = [[PreviewViewController alloc]initWithPreviewImage:[[kfxKEDImage alloc] initWithImage:imgCaptured] withSourceofCapture:_typeOfCapture typeOfDocumentCaptured:PHOTO];
[self presentViewController:previewController animated:YES completion:nil];
Dismissed the preview view controller.
[self dismissViewControllerAnimated:YES completion:nil];
Application goes into background then it is not crashed.
I selected two rows one after another. Application goes into background then it is crashed. I don't know why it is behaving like that. If anyone know the solution please tell me.
Thanks In Advance
I had this problem, it was caused by someone overriding 'dealloc' in a UIViewController category.
https://github.com/taphuochai/PHAirViewController/issues/13
#chrishulbert
Remove this:
- (void)dealloc
{
self.phSwipeHander = nil;
}
Replace dealloc with this:
/// This is so that phSwipeGestureRecognizer doesn't create a swipe gesture in *every* vc's dealloc.
- (BOOL)phSwipeGestureRecognizerExists {
return objc_getAssociatedObject(self, SwipeObject) ? YES : NO;
}
- (void)ph_dealloc
{
if (self.phSwipeGestureRecognizerExists) {
self.phSwipeHander = nil;
}
[self ph_dealloc]; // This calls the original dealloc.
}
/// Swizzle the method into place.
void PH_MethodSwizzle(Class c, SEL origSEL, SEL overrideSEL) {
Method origMethod = class_getInstanceMethod(c, origSEL);
Method overrideMethod = class_getInstanceMethod(c, overrideSEL);
if (class_addMethod(c, origSEL, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod))) {
class_replaceMethod(c, overrideSEL, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
} else {
method_exchangeImplementations(origMethod, overrideMethod);
}
}
/// Swizzle dealloc at load time.
+ (void)load {
SEL deallocSelector = NSSelectorFromString(#"dealloc"); // Because ARC won't allow #selector(dealloc).
PH_MethodSwizzle(self, deallocSelector, #selector(ph_dealloc));
}
I found a really good walk through of how to pass string values back from a ViewController to a calling ViewController and got it working perfectly. The example is really very good.
https://www.youtube.com/watch?v=YVikeoR3gYg
That said, the technique for passing back content seems relatively straight forward now that I have seen it, even if it's not that intuitive.
The example code however only includes two controllers. When I replicated the code using a much more detailed Storyboard, the code simply doesn't work. In my test app, I even embedded the calling Controller inside a NavigationController to see whether this would have an affect, but it still continued to work fine.
In my application, the ViewController is embedded within a NavigationController that is called via a SWRevealController segue class. I don't know if this is important or relevant but I am mentioning it.
I then call a CollectionViewController to choose an icon that should be passed back to the calling ViewController.
When I select the icon, I correctly identify the icon and pop
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
selectedIcon = [placeIcons objectAtIndex:indexPath.row];
NSLog(#"In IconCollectionViewControlled - selected %#", selectedIcon);
NSString *itemToPassBack = #"12345"; // Just testing any old string here...
// [self.delegate passBackIcon:selectedIcon]; // commenting out while testing
[self.delegate passBackIcon:itemToPassBack];
[self.navigationController popViewControllerAnimated:YES];
}
I get a correct trace suggesting that the right icon is selected. I would then expect that the text '12345' would be passed back to the calling Controller.
In my calling Controller, I have the following:
- (void)passBackIcon:(NSString *)iconName {
NSLog(#"Icon to use is %#", iconName);
}
But this just isn't being called at all (or at least I'm not seeing the NSLog being shown. It's just being ignored.
The delegate is being correctly declared as far as I can tell.
Am I missing something?
assuming you are working with segues, in the method prepareSegue you should setting the delegate
for Example :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"YOUR_SEGUE_IDENTIFIER"] ) {
DestinationVc *vc = (DestinationVc *)segue.destinationViewController;
[vc setDelegate:self];
}
}
Hope it works for you
I've found this to be the easiest way to pass string and other information around using a tableView.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
ViewControllerYouWantToPassToo *result = [self.storyboard instantiateViewControllerWithIdentifier:#"NameOfTheViewController"];
result.stringName = #"12345" // String Name is a NSString property you set up in the ViewController you want to pass too
[self.navigationController pushViewController:result animated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
I suggest you wrapping your delegate in a check to see that it is valid and that it has adopted the respective method (if optional).
if(self.delegate && [self.delegate respondsToSelector:#selector(passBackIcon:)]){
[self.delegate passBackIcon:itemToPassBack];
}else{
NSLog(#"Your delegate is not setup correctly");
}
If it enters the else, you have not set the delegate properly..ie you likely never did
self.delegate = SomeInstanceOfAClassThatAdoptsYourDelegate;
I'm developing an app which uses splitView.
I'm using two items in splitView (Called them Customer and Supplier).
When I click on one of them I just use one viewController to display (called it: ContactViewController) and I use collectionView to display its data. To get data I just code it:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (!dbManager.synchronized) {
if (contactType == ContactTypeCustomer)
[dbManager requestData:kDbCustomers predicate:nil target:self];
else if (contactType == ContactTypeSuppplier)
[dbManager requestData:kDbSuppliers predicate:nil target:self];
}
}
And when get successful:
#pragma mark
#pragma DBDelegate
- (void)requestDataCompleted:(NSMutableArray *)results
{
datasource = results;
[self.collectionView reloadData];
}
I use I3DragBetweenHelper downloaded from github.com
Embedded into my app to initial drag and drop. To do this, I call the below method into viewDidLoad of ContactViewController
- (void) initDragAndDrop
{
self.helper = [[I3DragBetweenHelper alloc] initWithSuperview:self.view
srcView:_collectionView
dstView:_collectionView];
self.helper.delegate = self;
self.helper.isDstRearrangeable = NO;
self.helper.isSrcRearrangeable = NO;
self.helper.doesSrcRecieveDst = NO;
self.helper.doesDstRecieveSrc = YES;
self.helper.hideDstDraggingCell = YES;
self.helper.hideSrcDraggingCell = NO;
}
The helper here is:
#property (strong, nonatomic) I3DragBetweenHelper *helper;
The problem is when I click on Supplier I can drag and drop the cell of collectionView into ContactViewController. Below method had called and worked:
- (BOOL)droppedOutsideAtPoint:(CGPoint)pointIn fromDstIndexPath:(NSIndexPath *)from
But when I click on Customer the above method doesn't call. I can't even drag my cell of collectionView into ContactViewController. Any help will appreciate.
Why is isDstRearrangeable set to NO ??? coz eventually you would grab something and drop it onto something ( dest ) and that something ( dest ) will be rearranged, am i wrong ??
does your drag and drop happen in the same place ?? ( i.e: UICollectionView )
if it does, then why do you have src as not rearrangeable ??? both your destination and src should be rearrangeable.
Try this and let me know how it goes :)
I dont know about this library but I think the problem is your srcView and dstView are the same. These should be different and must be either UITableView or UICollectionView.
If you are using UISplitViewController, its probably going to be the Master and Detail View Controllers used by the UISplitView
Okay I am kind of new to IOS development, but I am writing an application where I am using a timer class to time out the user if they idle too long on any particular scene in my storyboard and it bumps the user back to the original scene/view. I have a single story board that is made up of several scenes/views(not sure what the correct word here is), and each scene has its own view controller.
I accomplish the timeout via the appdelegate class. See code below.
So I have the code working and it works great, but I am trying to make it so that it will ignore the timer if we are on the main scene.
I have googled this, read copious amounts of documentation, and have tried many things but so far I haven't been able to figure out how to get the currently viewed scene in the applicationDidTimeout method.
If I can get the name of the currently viewed scene/view, then I can choose to ignore the timer or not.
Does anyone know how to do this?
Thank you for your time.
#import "StoryboardAppDelegate.h"
#import "TIMERUIApplication.h"
#implementation StoryboardAppDelegate
#synthesize window = _window;
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// applicaiton has timed out
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationDidTimeout:) name:kApplicationDidTimeoutNotification object:nil];
return YES;
}
-(void)applicationDidTimeout:(NSNotification *) notif
{
NSLog (#"time exceeded!!");
UIViewController *controller = [[UIStoryboard storyboardWithName:#"Main" bundle:NULL] instantiateViewControllerWithIdentifier:#"StoryboardViewController"];
UINavigationController * navigation = [[UINavigationController alloc]initWithRootViewController:controller];
[self.window setRootViewController:navigation];
navigation.delegate = self;
navigation.navigationBarHidden = YES;
if (controller) {
#try {
[navigation pushViewController:controller animated:NO];
} #catch (NSException * ex) {
//“Pushing the same view controller instance more than once is not supported”
//NSInvalidArgumentException
NSLog(#"Exception: [%#]:%#",[ex class], ex );
NSLog(#"ex.name:'%#'", ex.name);
NSLog(#"ex.reason:'%#'", ex.reason);
//Full error includes class pointer address so only care if it starts with this error
NSRange range = [ex.reason rangeOfString:#"Pushing the same view controller instance more than once is not supported"];
if ([ex.name isEqualToString:#"NSInvalidArgumentException"] &&
range.location != NSNotFound) {
//view controller already exists in the stack - just pop back to it
[navigation popToViewController:controller animated:NO];
} else {
NSLog(#"ERROR:UNHANDLED EXCEPTION TYPE:%#", ex);
}
} #finally {
//NSLog(#"finally");
}
} else {
NSLog(#"ERROR:pushViewController: viewController is nil");
}
[(TIMERUIApplication *)[UIApplication sharedApplication] resetIdleTimer];
}
#end
I'm assuming you've written the logic for the timer somewhere. Can you just invalidate the timer when you've popped back to the rootViewController?
Also instead of pushing a viewController onto the navigationViewController and handling the errors, you should check to see if the controller you're pushing is already in the stack like so:
if (![navigation.viewControllers containsObject:viewController] {
// push onto the stack
}
You could also check to see how many levels are currently in the navigationController by checking the count of the viewControllers array like so:
if ([navigation.viewControllers count] == 0) {
// I know we're on the main screen because no additional viewControllers have been added to the stack.
}
If you are not using modal controllers anywhere then the simplest solution would be
UINavigationController* nav = (UINavigationController*)self.window.rootViewController; // You could just save the nav as part of your app delegate
if (nav.viewControllers.count > 1){
[nav popToRootViewControllerAnimated:YES];
}
This is different then your current code because your main page will not be deleted and recreated every time the timer goes off
Okay I figured out how to do this. I was making this way too complicated.
To solve this I simply made a property and method in the app delegate class where I could set a scene name.
Then in each view controller header file I import the header file for the app delegate class and define a reference to it. Then in the load event for each view I simply set the scene name in the app delegate class using this line of code.
[myAppDelegate setSceneName:self.title];
Easy peasy!