Updating a BOOL value from another class - ios

I have setup a class with the following:
MESSidePanelViewControllerSubClass
Header file
#property BOOL setLandscapeOK;
Imp file
- (NSInteger)supportedInterfaceOrientations {
// Restriction for the welcome page to only allow potrait orientation
if (setLandscapeOK == YES) {
NSLog(#"Reveal-setting all");
return UIInterfaceOrientationMaskAll;
}
NSLog(#"Reveal-setting portrait");
return UIInterfaceOrientationMaskPortrait;
}
I now want to update the value from another file (view controller).
LoginViewController
Other view controller imp file
- (NSInteger)supportedInterfaceOrientations {
// Restriction for the welcome page to only allow potrait orientation
NSLog(#"Login-supportInterfaceOrientations");
MESSidePanelViewControllerSubClass* setLandscapeOK = YES;
return UIInterfaceOrientationMaskAll;
}
I get an error:
Implicit conversion of 'BOOL' (aka 'signed char') to 'MESSidePanelViewControllerSubClass *' is disallowed with ARC
How should I be updated the BOOL value in another file?

This line is wrong:
MESSidePanelViewControllerSubClass* setLandscapeOK = YES;
It should be something like this: (Also mESSidePanelViewControllerSubClass is probably an iVar and instantiated somewhere outside your supportedInterfaceOrientations method.)
MESSidePanelViewControllerSubClass *mESSidePanelViewControllerSubClass = [MESSidePanelViewControllerSubClass alloc] init];
then:
mESSidePanelViewControllerSubClass.setLandscapeOK = YES;
Edited to add link to delegate.

Shouldn't -supportedInterfaceOrientations in MESSidePanelViewControllerSubClass always return UIInterfaceOrientationMaskPortrait? If an instance of MESSidePanelViewControllerSubClass is pushed as a child view controller, won't that force your UI orientation to be portrait? Did you try that?

Related

iOS: How to change Orientation of only one view controller in app?

I am facing problem in view orientation in my app.
Like
I have two view controller, VC1 and VC2
VC1 have fix landscape orientation.
VC2 have both
VC1 -> VC2 is fine. means when I go from VC1 to VC2, VC2 change its orientation in both landscape and portrait.
But when I comeback to VC1 from VC2(where VC2 in portrait mode), VC1 also is in portrait mode but I want VC1 is in landscape only irrespective of VC2 mode.
Please guys help me. Seeking solution from last 2 days.
Thanks in advance.
Refer below link for solution
http://swiftiostutorials.com/ios-orientations-landscape-orientation-one-view-controller/
In your VC1..
-(BOOL)shouldAutorotate
{
return NO;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeLeft;
}
Hope it helps you...
First of all, write this in AppDelegate.m
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return (UIInterfaceOrientationMaskAll);
}
Then, For VC1, in which landscape orientation, write this:
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return (UIInterfaceOrientationMaskPortrait);
}
For VC2, which have both, change masking to All.
- (NSUInteger)supportedInterfaceOrientations
{
return (UIInterfaceOrientationMaskAllButUpsideDown);
//OR return (UIInterfaceOrientationMaskAll);
}
1. Enable all orientation support for project.
For VC1 Add this line VC1Controller Class
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape;
}
For VC2 Add this in VC2Controller Class
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAll;
}
basically the view-controller-based orientation support in an iOS app is a piece of cake – I did the code in Swift, but ObjC concept would be totally identical to this.
I have created a quick tutorial with UINavigationController but you can convert that to UITabBarController by keeping the concept but updating the environment slightly.
step-1
initially set the orientation support for your app like this:
step-2
create a simple UINavigationController-based storyboard like this:
NOTE: don't worry if it does not say initially OrientaionSupporterController (bonus point if you'd spot the consistent typo here!), I will cover that just in the very next step.
step-3
create a subset of the navigation-controller, like this:
import UIKit
// MARK: - Implementation
class OrientaionSupporterController: UINavigationController {
// MARK: - Active View Controller
private var activeViewController: UIViewController? {
get {
return self.presentedViewController ?? self.topViewController // for possible modal support
}
}
// MARK: - Orientations
override var shouldAutorotate: Bool {
get {
return self.activeViewController?.shouldAutorotate ?? true // yes, rotate it, please
}
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return self.activeViewController?.supportedInterfaceOrientations ?? .all // default is all possible orientations
}
}
then make sure the that becomes the base class in IB as well:
step-3
create the individual view-controllers with custom orientation support, like e.g. with only portrait and landscape-left support:
import UIKit
// MARK: - Implementation
class ViewController: UIViewController {
// MARK: - Orientation
override var shouldAutorotate: Bool {
get {
return true
}
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return [.portrait, .landscapeLeft] // no one find that preactical but works flawlessly
}
}
NOTE: you can convert this tutorial anytime with UITabBarController, you just need to (obviously) create a subset of the tab-bar-controller and use the selectedViewController to get the currently visible one.
NOTE#2: obviously you can go much further on this way and you can nest the customised navigation-controllers in the view hierarchy, or if you have multiple UIWindow instances in the queue and override the supported orientations there as well for each individual windows (e.g. some support all four orientations, while some other windows does only landscape for e.g. video playback, etc...)

Trouble setting bool value of destination view controller in segue

As I segue from SearchViewController to MatchCenterViewController, I want to set the bool value of _didAddNewItem in MatchCenterViewController to YES. I'm attempting to accomplish this like so:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"ShowMatchCenterSegue"]) {
MatchCenterViewController *controller = (MatchCenterViewController *) segue.destinationViewController;
_didAddNewItem = YES;
NSLog(#"we're about to set controller values before segueing to MC");
// Send over the matching item criteria
controller.itemPriority = self.itemPriority;
if (_didAddNewItem == YES) {
NSLog(#"Did add new item is YES");
}
[self.tabBarController setSelectedIndex:1];
}
}
The destination view controller is tab 1, so I want to set the bool before it switches to that tab. It is logging out "Did add new item is YES", which tells me that the value of the bool is indeed YES just before segueing.
However, upon switching to the destination, when the viewDidAppear of the destination controller runs, it logs out "don't refresh".
- (void)viewDidAppear:(BOOL)animated
{
if (_didAddNewItem == YES) {
NSLog(#"well then lets refresh the MC");
}
else if (_didAddNewItem == NO) {
NSLog(#"dont refresh");
}
}
I set the bool property in the headers of both originating and destination VC like so:
#property (assign) BOOL didAddNewItem;
Very confused as to what I'm missing here.
You are confusing access to a property with access to the automatically synthesised iVar.
When you say
#property BOOL something;
and don't use an #synthesize statement the compiler will automatically create an iVar BOOL _something to store the property. You can then access this property using self.something or _something. You should get into the habit of always using self.something (or object.something in the case of another object reference) except in initialiser methods.
In your code you are setting the local iVar _didAddNewItem when what you want is to set the property on the destination controller -
controller.didAddNewItem = YES;

Passing a conditional statement when pushing viewControllers using storyboards

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 {
}
}

Autorotation in iOS 6.1 for custom camera view

I've read almost every post around here regarding my problem but none of the solutions seems to work on my app.
So, I use a custom camera view (with buttons on toolbar and an overlay) that is being presented modally from a view controller. My app only supports landscape left and right for the orientation. And i want to stop the camera view from autorotating when it's being presented. I've put all the methods needed for autorotation on my view controller and my app delegate. I've checked on my plist file too and the supported rotations are correct. But my camera view keeps on rotating to any rotation (portrait and landscape) when I rotate the device, resulting on the overlay and the toolbar being incorrectly positioned. I also can't check on the camera view's orientation because i tried putting NSLog on shouldAutoRotate method, but it doesn't get called at all.
So how can I check the rotation on my custom camera view? And how can I force it to not rotate and stay still?
If my code is needed, I'll post it here. If anyone can help me on it I'll greatly appreciate it because it frustrates me so much right now.
Thank you. Cheers.
Create a new class of "UIImagePickerController" and implement the rotation delegates in the .m file as given,
// For lower iOS versions
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return ((toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) || ((toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)));
}
// For iOS version 6.0 and above
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return (UIInterfaceOrientationMaskLandscape);
}
And make an instance of lets say MyImagePickerController instead of UIImagePickerController, and present it. This will work :)
Create a category for UINavigationController
#interface UINavigationController(autoRotation)
-(BOOL)shouldAutoRotate;
#end
#implementation UINavigationController
-(BOOL)shouldAutoRotate{
return [[self.viewControllers lastobject] shouldAutoRoatate];
}
-(NSUInteger)supportedInterfaceOrientations {
return [[self.viewControllers lastobject] supportedInterfaceOrientations];
}
#end
Implement these two methods in your corresponding view controllers
and return the orientation what u exactly want....
xcode -> file -> new file select cocotouch in the leftpane select objective-c category ->next
select give name Picker category on UIImageImagePickerController from dropdown
import
#interface UIImagePickerController (picker)
-(BOOL)shouldAutoRotate;
-(NSUInteger)supportedInterfaceOrientations;
#end
import "UIImagePickerController+picker.h"
#implementation UIImagePickerController (picker)
-(BOOL)shouldAutoRotate{
return yourOrientation;
}
-(NSUInteger)supportedInterfaceOrientations {
return yourInteger;
}
#end
After this when your device's orientation changed then the method shouldAutoRotate get called from your UINavigationController category at this time you have to find out if cameraview is presented if yes then you have to call shouldAutoRotate of Picker
See the following code
in your view controller's shouldAutoRotate
-(BOOL)shouldAutoRotate{
if([self presentingViewController])// Camera is present
return [instanceOfUIImagePickerController shouldAutoRotate];
return yourOrientaionNeededForThisVC;
}

How to tell if UIViewController's view is visible

I have a tab bar application, with many views. Is there a way to know if a particular UIViewController is currently visible from within the UIViewController? (looking for a property)
The view's window property is non-nil if a view is currently visible, so check the main view in the view controller:
Invoking the view method causes the view to load (if it is not loaded) which is unnecessary and may be undesirable. It would be better to check first to see if it is already loaded. I've added the call to isViewLoaded to avoid this problem.
if (viewController.isViewLoaded && viewController.view.window) {
// viewController is visible
}
Since iOS9 it has became easier:
if viewController.viewIfLoaded?.window != nil {
// viewController is visible
}
Or if you have a UINavigationController managing the view controllers, you could check its visibleViewController property instead.
Here's #progrmr's solution as a UIViewController category:
// UIViewController+Additions.h
#interface UIViewController (Additions)
- (BOOL)isVisible;
#end
// UIViewController+Additions.m
#import "UIViewController+Additions.h"
#implementation UIViewController (Additions)
- (BOOL)isVisible {
return [self isViewLoaded] && self.view.window;
}
#end
There are a couple of issues with the above solutions. If you are using, for example, a UISplitViewController, the master view will always return true for
if(viewController.isViewLoaded && viewController.view.window) {
//Always true for master view in split view controller
}
Instead, take this simple approach which seems to work well in most, if not all cases:
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
//We are now invisible
self.visible = false;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
//We are now visible
self.visible = true;
}
For those of you looking for a Swift 2.2 version of the answer:
if self.isViewLoaded() && (self.view.window != nil) {
// viewController is visible
}
and Swift 3:
if self.isViewLoaded && (self.view.window != nil) {
// viewController is visible
}
For over-full-screen or over-context modal presentation, "is visible" could mean it is on top of the view controller stack or just visible but covered by another view controller.
To check if the view controller "is the top view controller" is quite different from "is visible", you should check the view controller's navigation controller's view controller stack.
I wrote a piece of code to solve this problem:
extension UIViewController {
public var isVisible: Bool {
if isViewLoaded {
return view.window != nil
}
return false
}
public var isTopViewController: Bool {
if self.navigationController != nil {
return self.navigationController?.visibleViewController === self
} else if self.tabBarController != nil {
return self.tabBarController?.selectedViewController == self && self.presentedViewController == nil
} else {
return self.presentedViewController == nil && self.isVisible
}
}
}
You want to use the UITabBarController's selectedViewController property. All view controllers attached to a tab bar controller have a tabBarController property set, so you can, from within any of the view controllers' code:
if([[[self tabBarController] selectedViewController] isEqual:self]){
//we're in the active controller
}else{
//we are not
}
I made a swift extension based on #progrmr's answer.
It allows you to easily check if a UIViewController is on screen like so:
if someViewController.isOnScreen {
// Do stuff here
}
The extension:
//
// UIViewControllerExtension.swift
//
import UIKit
extension UIViewController{
var isOnScreen: Bool{
return self.isViewLoaded() && view.window != nil
}
}
For my purposes, in the context of a container view controller, I've found that
- (BOOL)isVisible {
return (self.isViewLoaded && self.view.window && self.parentViewController != nil);
}
works well.
I use this small extension in Swift 5, which keeps it simple and easy to check for any object that is member of UIView.
extension UIView {
var isVisible: Bool {
guard let _ = self.window else {
return false
}
return true
}
}
Then, I just use it as a simple if statement check...
if myView.isVisible {
// do something
}
I hope it helps! :)
Good point that view is appeared if it's already in window hierarchy stack.
thus we can extend our classes for this functionality.
extension UIViewController {
var isViewAppeared: Bool { viewIfLoaded?.isAppeared == true }
}
extension UIView {
var isAppeared: Bool { window != nil }
}
XCode 6.4, for iOS 8.4, ARC enabled
Obviously lots of ways of doing it. The one that has worked for me is the following...
#property(nonatomic, readonly, getter=isKeyWindow) BOOL keyWindow
This can be used in any view controller in the following way,
[self.view.window isKeyWindow]
If you call this property in -(void)viewDidLoad you get 0, then if you call this after -(void)viewDidAppear:(BOOL)animated you get 1.
Hope this helps someone. Thanks! Cheers.
if you're utilizing a UINavigationController and also want to handle modal views, the following is what i use:
#import <objc/runtime.h>
UIViewController* topMostController = self.navigationController.visibleViewController;
if([[NSString stringWithFormat:#"%s", class_getName([topMostController class])] isEqualToString:#"NAME_OF_CONTROLLER_YOURE_CHECKING_IN"]) {
//is topmost visible view controller
}
The approach that I used for a modal presented view controller was to check the class of the presented controller. If the presented view controller was ViewController2 then I would execute some code.
UIViewController *vc = [self presentedViewController];
if ([vc isKindOfClass:[ViewController2 class]]) {
NSLog(#"this is VC2");
}
I found those function in UIViewController.h.
/*
These four methods can be used in a view controller's appearance callbacks to determine if it is being
presented, dismissed, or added or removed as a child view controller. For example, a view controller can
check if it is disappearing because it was dismissed or popped by asking itself in its viewWillDisappear:
method by checking the expression ([self isBeingDismissed] || [self isMovingFromParentViewController]).
*/
- (BOOL)isBeingPresented NS_AVAILABLE_IOS(5_0);
- (BOOL)isBeingDismissed NS_AVAILABLE_IOS(5_0);
- (BOOL)isMovingToParentViewController NS_AVAILABLE_IOS(5_0);
- (BOOL)isMovingFromParentViewController NS_AVAILABLE_IOS(5_0);
Maybe the above functions can detect the ViewController is appeared or not.
If you are using a navigation controller and just want to know if you are in the active and topmost controller, then use:
if navigationController?.topViewController == self {
// Do something
}
This answer is based on #mattdipasquale's comment.
If you have a more complicated scenario, see the other answers above.
you can check it by window property
if(viewController.view.window){
// view visible
}else{
// no visible
}
I needed this to check if the view controller is the current viewed controller, I did it via checking if there's any presented view controller or pushed through the navigator, I'm posting it in case anyone needed such a solution:
if presentedViewController != nil || navigationController?.topViewController != self {
//Viewcontroller isn't viewed
}else{
// Now your viewcontroller is being viewed
}
Window:
window.isVisible
viewController.view.window?.isVisible ?? false
View (macOS):
extension NSViewController {
var isOnScreen: Bool {
return ( self.isViewLoaded && view.window != nil )
}
}

Resources