Adding Google Cardboard SDK to a React Native project - objective-c

I'm currently working on a React Native application that amongst other things, it needs to show a panorama using the Google Cardboard SDK. I seem to have most of the things set up but given my very limited knowledge on Objective-C, I am not able to connect all ports of the puzzle.
Currently, I have my javascript connecting with objective-c so that's all fine however, looking at the example code in the Cardboard SDK, a PanoramaViewController of type UIViewController is defined and the necessary elements of the page (text, actual panorama viewer, etc) are added to the view using something like:
[_scrollView addSubview:_panoView];
In my case, given that i am defining my ViewController with type NSObject RCTBridgeModule, if I understand correctly, I am not able to do this, unless i'm not missing something else.
I've been looking around to try and find what's the best way of going about this and what I found was something along these lines:
UIViewController *rootController = UIApplication.sharedApplication.delegate.window.rootViewController;
[rootController presentViewController:MyViewController animated:YES completion:nil];
In the above, I don't know what exactly do I have to pass instead of MyViewController given that to my understanding, the Cardboard SDK only creates the view and I am responsible of creating the actual ViewController.
At the moment, this is how my ViewController.h looks like:
#import <Foundation/Foundation.h>
#import "RCTBridge.h"
#interface GCViewController : NSObject <RCTBridgeModule>
#end
and this is how my ViewController.m looks like:
#import "GCViewController.h"
#import "AppDelegate.h"
#import "RCTLog.h"
#import "GCSPanoramaView.h"
#interface GCViewController ()<GCSWidgetViewDelegate>
#end
#implementation GCViewController {
GCSPanoramaView *_panoView;
}
RCT_EXPORT_MODULE();
-(void)show360Video {
_panoView = [[GCSPanoramaView alloc] init];
_panoView.delegate = self;
_panoView.enableFullscreenButton = YES;
_panoView.enableCardboardButton = YES;
[_panoView loadImage:[UIImage imageNamed:#"test.jpg"]
ofType:kGCSPanoramaImageTypeMono];
UIViewController *rootController = UIApplication.sharedApplication.delegate.window.rootViewController;
[rootController presentViewController:XXXXXX animated:YES completion:nil];
}
RCT_EXPORT_METHOD(showVideo) {
[self show360Video];
}
#end
I would appreciate if anyone can help me on this. Thanks!
PS: in this project i'm using the Google Cardboard v0.7.2 and not the new Google VR library.

You can use rootController Which is defined before that error.Thanks

Related

Why is this delegate method automatically called in Objective-C?

I'm going through this book called "cocoa programming for mac os x" and I just started with delegates. This whole thing with delegates is still a little bit wacky to me but I think I just need to let it settle.
However there was this one exercise where I should implement a delegate of the main window so that if resized height is always 2xwidth.
So I got 4 files:
AppDelegate.h
AppDelegate.m
WindowDelegate.h
WindowDelegate.m
AppDelegate are just the two standard files that get created when you open a new Cocoa project. I had to look up the solution because I didn't quite know how to accomplish this task.
The solution was just to create a new cocoa class, "WindowDelegat.h/.m" and add this to it's implementation file:
- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize {
NSSize newSize = frameSize;
newSize.height = newSize.width * 2;
return newSize;
}
Then I opened the interface builder, added a new object and made it my WindowDelegate. I then had to ctrl drag from the WindowDelegate to the actual window and made it the window's delegate.
Clicked run and it worked. Yay! But why?
First I thought that "windowWillResize" is just one of these callback functions that get's called as soon as the window is resized but it isn't. Normally methods get invoked because the general lifecycle of an program invokes them or because they are an #IBAction, a button or different control elements.
But "windowWillResize" is non of them. So why is it called?
EDIT: Problem solved! Thanks a lot!
Now I'm trying to connect the delegate to the window programmatically. Therefore I deleted the referencing outlet from WindowDelegate to the actual window in interface builder. It works but I just want to verify that this it the correct way how it's done:
AppDelegate.h
#import <Cocoa/Cocoa.h>
#import "WindowDelegate.h"
#interface AppDelegate : NSObject <NSApplicationDelegate>
#end
AppDelegate.m
#import "AppDelegate.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
#property (strong) WindowDelegate *winDeleg;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
- (void)awakeFromNib {
[_window setOpaque:NO];
NSColor *transparentColor = [NSColor colorWithDeviceRed:0.0 green:0.0 blue:0.0 alpha:0.5];
[_window setBackgroundColor:transparentColor];
NSSize initialSize = NSMakeSize(100, 200);
[_window setContentSize:initialSize];
_winDeleg = [[WindowDelegate alloc] init];
[_window setDelegate: _winDeleg];
}
#end
WindowDelegate.h
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#interface WindowDelegate : NSObject <NSWindowDelegate>
#end
WindowDelegate.m
#import "WindowDelegate.h"
#implementation WindowDelegate
- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize {
NSSize newSize = frameSize;
newSize.height = newSize.width * 2;
return newSize;
}
- (id)init {
self = [super init];
return self;
}
#end
Why does the #property of WindowDelegate need to be strong?
And isn't my winDeleg an object? Why do I have to access it through _winDeleg when it's an object. I though the underscore is used to access variables?
Thank you for your help!
Clicked run and it worked. Yay! But why?
Because instances of NSWindow have a delegate property that can point to any object that implements the NSWindowDelegate protocol, and that protocol includes the -windowWillResize:toSize: method.
Read that a few times. The reason it's important is that you can create your own object, say that it implements NSWindowDelegate, implement -windowWillResize:toSize:, and set that object as your window's delegate. Then, whenever the user resizes the window, your method will be called and can modify the proposed new size.
Normally methods get invoked because the general lifecycle of an program invokes them or because they are an #IBAction, a button or different control elements. But "windowWillResize" is non of them. So why is it called?
This really isn't so different. Think of delegates as "helper objects." They let you customize the behavior of an object without having to create a whole new subclass. The NSWindowDelegate object is essentially a contract that the NSWindow promises to follow: whenever certain things happen, such as the user resizing the window, the window will call certain methods in its delegate object, if the delegate exists and implements those methods. In the case of NSApplication, a lot of those delegate methods are application lifecycle events, like the app starting up or quitting or getting a message from the operating system. In the case of NSWindow, delegate methods correspond to interesting events that can happen to a window, like the user moving it, hiding it, showing it, maximizing it, moving it to a different screen, etc. Other classes, like text views or network connections or movie players, have their own sets of interesting events and their own delegate protocols to match.
Note that methods marked IBAction really aren't delegate methods, they're just methods that get called by objects like controls that use a target/action paradigm. The IBAction keyword lets the IDE know which methods it should present as possible actions for things like buttons. You often find actions in window controllers and view controllers, and those objects frequently act as a delegate for some other object, but the actions themselves aren't part of the delegate protocol. For example, NSTableView takes a delegate object that determines how the table will act and what's displayed in it. It often makes sense for the view controller that manages the table to be the table's delegate, and that same view controller might also manage some buttons and contain the action methods that said buttons trigger, but the actions aren't part of the NSTableViewDelegate protocol and you therefore wouldn't call them delegate methods.

Window ordering and XIB

I am setting my first steps in OSX development and I've run into some problems. I have quite some experience with iOS development but the window system for OSX programs is something else.
I am making a client for a social network like twitter and need 2 seperate window controller for first starting the app, one if you are logged in to show your timeline and one for logging in, if you are not yet logged in. In the info.plist you need to give it a main.xib. For this I made an empty xib which I hide, the second the app starts. This is not really a good solutions IMO, what is a better solution for this? I want to keep the windows seperate from the appdelegate because that way I can keep my code seperated.
This gives me a problem, when I open my 'second' window to login it shows up but isn't active. I have tried all the things like, orderFront:, activateIgnoringOtherApps:, makeKeyAndOrderFront: & more. But this all doesn't work..
So: First off, is there a better way to handle the main.xib that is needed in the info.plist and if not, is there a way around the focus problem?
I'm working om osx 10.7
For more than one-offs, you really ought to separate your app delegate from your window controllers. Go ahead and create a new Cocoa application from the template. In MainMenu.xib, delete the window. In AppDelegate.h delete the IBOutlet to the NSWindow. Create a couple new subclasses of NSWindowController complete with XIBs--perhaps LoginWindowController and TimelineWindowController.
For "final" NSWindowController subclasses (i.e. those which won't be subclassed), the best practice for designated initializers is
//for our example class LoginWindowController
- (id)init
{
self = [super initWithWindowNibName:#"LoginWindowController"];
if (self) {
//....
}
return self;
}
Now in your app delegate, you should have #properties for the two different window controller instances:
//Within AppDelegate.m
#import "AppDelegate.h"
#import "LoginWindowController.h"
#import "TimelineWindowController.h"
#interface AppDelegate ()
#property (nonatomic) LoginWindowController *loginWindowController;
#property (nonatomic) TimelineWindowController *timelineWindowController;
//For the sake of this demo, add a property for the loggedIn state:
#property (nonatomic) BOOL loggedIn;
#end
You ought to have some sort of method in your app delegate that presents the correct window controller. Let's call it -updateWindowVisibility:
- (void)updateWindowVisibility
{
BOOL isLoggedIn = self.loggedIn;
BOOL loginWindowVisible = self.loginWindowController.window.isVisible;
BOOL showLoginWindow = !isLoggedIn;
BOOL timelineWindowVisible = self.timelineWindowController.window.isVisible;
BOOL showTimelineWindow = isLoggedIn;
if (!loginWindowVisible && showLoginWindow) {
if (!self.loginWindowController) self.loginWindowController = [[LoginWindowController alloc] init];
[self.loginWindowController showWindow:nil];
} else if (loginWindowVisible && !showLoginWindow) {
[self.loginWindowController close];
self.loginWindowController = nil;
}
if (!timelineWindowVisible && showTimelineWindow) {
if (!self.timelineWindowController) self.timelineWindowController = [[TimelineWindowController alloc] init];
[self.timelineWindowController showWindow:nil];
} else if (timelineWindowVisible && !showTimelineWindow) {
[self.timelineWindowController close];
self.timelineWindowController = nil;
}
}
This method as implemented above does a tiny bit more work than is necessary given the present setup, but should be easier to modify when you need to show/hide other windows. All that's left to do at this point is to call -updateWindowVisibility from -applicationDidFinishLaunching:.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
self.isLoggedIn = NO;
[self updateWindowVisibility];
}
I've posted an example app to github which demonstrates this approach.
In terms of structure (your first question), I would recommend this:
Create a XIB with one blank window and a big NSView (called, say, megaView) covering it. Create an IBOutlet in AppDelegate for your big NSView. Set the app to use this XIB on load.
Create two separate NSView XIBs: one for the state of being logged in, one for the state of being logged out. Put your layout in these.
Create two NSViewController subclasses: one controlling the logic of each NSView you just created. Let's call them LoggedOutViewController and LoggedInViewController.
Jump back to the two NSViews you created. Set the File Owner of your logged in NSView to LoggedInViewController and the File Owner of your logged out NSView to LoggedOutViewController. Hook up each File Owner's view (right-click on File Owner to find it) to the respective NSView.
In your app delegate, determine the user's authentication status in whatever way you need.
If logged in, do this:
NSViewController *loggedInController = [[NSViewController alloc] initWithNibName:#"NibNameGoesHere" bundle:nil];
[[self megaView] addSubview:[loggedInController view]];
Otherwise do the above process with your loggedOutController:
NSViewController *loggedOutController = [[NSViewController alloc] initWithNibName:#"OtherNibNameGoesHere" bundle:nil];
[[self megaView] addSubview:[loggedOutController view]];
That should get you what you want and will likely clear up your second question in the process. The difference between my answer and Nate's is that mine uses the same window. Instantiating view controllers conditionally and loading their views into superviews is probably the most important aspect of Cocoa I learned.

Push to UIViewController dynamically

I am a newbie in iPhone application development.
I am developing an iPad application. It contains a menu bar on top, clicking on which retrieves a sub view. The sub view consists of UIPickerView. Upon selecting a row from UIPickerView, navigates to another UIViewController.
The UIPickerView methods are written in a separate class (As this functionality comes throughout the app, I made it a general one). So,
[self.navigationController pushViewController:controller animated:YES];
will not work for me!
I was able to get the name of the class to be pushed (It changes according to the selection made). Is there any way I can do it?
Thanks In Advance :-)
I guess what you really want is to create an object from a classname
The simple answer is
[[NSClassFromString(className) alloc] init...]
For a more thorough answer you should look at Create object from NSString of class name in Objective-C
You can use delegate method (delegate methods allows communication between objects) to implement this scenario
For example in your UIPicker(.h) class define a delegate protocol as follows
#protocol pickerProtocol;
#interface MyPicker : NSObject {
id <pickerProtocol> pickerDelegate;
}
#property(nonatomic,retain) id <pickerProtocol> pickerDelegate;
#end
#protocol pickerProtocol
- (void) pushViewController;
#end
And call this delegate method when selecting a row from UIPickerView
[pickerDelegate pushViewController];
Then in all view controller that uses picker write the implementation of the delegate method
- (void) pushViewController {
[self.navigationController pushViewController:controller animated:YES];
}
dont for get to set the delegate as follows
MyPicker *picker = [MyPicker alloc]init];
picker.pickerDelegate = self;

Dismissing view using delegation not working

I am trying to use delegation, which I am new at, to dismiss a modally presented view. I am trying to get it to work along the lines of the apple documentation seen here. So far my code is as follows:
Put both views on storyboard, connect first to second view with modal segue. (the segue to view2 works fine)
create delegate inside second viewcontroller/create method to call when returned:
//inside of view2ViewController.h
#class view2ViewController;
#protocol view2ViewControllerDelegate <NSObject>
-(void)goBack:(OptionsViewController *)controller;
#end
#interface OptionsViewController : UIViewController
#property (nonatomic, weak) id <view2ViewControllerDelegate>delegate;
- (IBAction)return:(id)sender;//connected to button
#end
implement delegate in view1ViewController #interface view1ViewController : UIViewController <view2ViewControllerDelegate>
write code for delegate method goBack in view1Controller.m
-(void)goBack:(view2ViewController *)controller{
[self dismissViewControllerAnimated:YES completion:nil];}
finish by writing code for return method in view2ViewController.m
- (IBAction)return:(id)sender {
[self.delegate goBack:self];}
I'm not sure where this code is going wrong. The return method is called, but then goBack isn't. I did read the developer documentation, and thought I understood, but I guess not...
PS I change the names of all of my class/variable names on StackOverflow to be more generic, so if there is a slight discrepancy between variable name spellings, it's probably because i typed one wrong.
The best shot I can try -
Make sure you assigned the SplashViewController as the delegate of the view2ViewController.
By code you can do it like that (in the SplashViewController m file):
view2ViewController.delegate = self;
Or you can do to on Story board.
BTW
I a not sure calling your function "return" is a good idea.

PreferencesViewControllerDelegate

I found this in some example code I downloaded
#import "PreferencesViewController.h"
#class MetronomeView;
#interface MetronomeViewController : UIViewController <PreferencesViewControllerDelegate> {
MetronomeView *metronomeView;
}
#property (nonatomic, assign) IBOutlet MetronomeView *metronomeView;
- (IBAction)showInfo;
#end
I tried to find information on PreferencesViewControllerDelegate, but didn't find much. What is this delegate?
It's a custom view controller delegate protocol that is created by Apple, for use in the Metronome sample project (and I imagine others). The protocol declaration can be found here, and how it's implemented can be seen here.
All it does is act as a delegate that monitors what happens to PreferencesViewController, the controller that manages the preferences view.
The protocol contains one method called preferencesViewControllerDidFinish:, which is implemented by MetronomeViewController like this. When the delegate receives a signal that the preferences view has been dismissed with the Done button, this is called to hide the view:
- (void)preferencesViewControllerDidFinish:(PreferencesViewController *)controller {
[self dismissModalViewControllerAnimated:YES];
}
A similar delegate called FlipsideViewControllerDelegate can be found in the Xcode iOS project template for a Utility Application.
This looks like a custom delegate created by whoever wrote the code you downloaded. It's not an Apple delegate, since it doesn't start with any of Apple's two-letter prefixes.