How do I respond to the user shaking an iPhone? - objective-c

Alright, so to get going with Objective-C (I'm usually just an HTML PhoneGap kinda guy), I made a simple Magic 8 ball app. I've got it right now so that when I touch the screen, the ball "shakes" and takes a random response and puts it in a label. What I want to do is when the iPhone itself is shaked, the text is updated too.
Here's my MainView.m:
#import "MainView.h"
#implementation MainView
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (event.type == UIEventSubtypeMotionShake) {
int rNumber = rand() % 26;
switch (rNumber) {
case 0:
shook.text = #"Never";
break;
....25 more entries.....
default:
break;
}
}
}
- (IBAction)yesNo {
[NSThread sleepForTimeInterval:0.75];
int rNumber = rand() % 26;
switch (rNumber) {
case 0:
result.text = #"Never";
break;
........
default:
break;
}
}
#end
and my MainView.h
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#interface MainView : UIView <UIAccelerometerDelegate> {
IBOutlet UILabel *result;
IBOutlet UILabel *shook;
}
- (IBAction)yesNo;
- (void)motionEnded;
#end
Obviously there's an error in there, I know that much, but where?!

It looks like you need to read the documentation in more depth to get to the bottom of this. Specifically the iOS Event Handling Guide.
From that document there are a few things which I would suggest you try:
Override canBecomeFirstResponder: and return YES (as per Listing 4-1).
Override viewDidAppear:animated: to become the first responder (as per Listing 4-1).
Override both motionBegan:withEvent: and motionCancelled:withEvent: as they do this in the example which may be because the framework is testing your view controller class to see if it responds to these selectors (as per Listing 4-2).
Look at the UIResponder Class Reference (from which UIViewController inherits) for more detail on the methods you are overriding.
As someone who came from a Microsoft / VB / .NET and Android / Java background to Cocoa / Objective-C programming I would strongly suggest you invest the time in reading the documentation. Initially the Apple documents seem impenetrable but they're actually pretty good!
I hope that helps.

Related

Adding Google Cardboard SDK to a React Native project

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

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.

How to move legal link in mkmapview IOS 7

as all we know Apple, we always need to change something for each update. Did somebody solve the moving problem for map legal link?
I tried many ways to control legal label but, just it can be hidden?
what else I can do?
thanks in advance
You need to change bottomLayoutGuide for your UIViewController. Create a class with following code:
MapLayoutGuide.h
#interface MapLayoutGuide : NSObject <UILayoutSupport>
-(id)initWithLength:(CGFloat)length;
#end
MapLayoutGuide.m
#import "MapLayoutGuide.h"
#implementation MapLayoutGuide
#synthesize length = _length;
- (id)initWithLength:(CGFloat)length
{
if (self = [super init])
{
_length = length;
}
return self;
}
#end
And then in your UIViewController, that is displaying map, add this:
-(id <UILayoutSupport>)bottomLayoutGuide
{
return [[MapLayoutGuide alloc] initWithLength:kMapViewBottomContentInset];
}
where kMapViewBottomContentInset - how much do you want to lift up Legal link. Typically size of UITabBar, if you have one.
This solution works even if you don't use AutoLayout on your view.
You can increase the height of the map so that the legal label is hidden by another view or something. I saw that some people placed a "locate me" button on top of it. I don't think that there is an easy (or legal) way to reposition or remove it.
override func viewWillLayoutSubviews() {
positionLegalMapLabel()
}
func positionLegalMapLabel() {
let legalMapLabel = self.mapView.subviews[1]
legalMapLabel.frame.origin = CGPointMake(self.mapView.bounds.size.width - legalMapLabel.frame.size.width - 7, legalMapLabel.frame.origin.y)
}

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.

HOWTO: Is NSWindow In FullScreen Mode (Lion) AND Enabling/Disabling?

I spent a great deal of time figuring out how to determine if my NSWindow is in full screen mode or not and also how to enable/disable it from going in or out of full screen mode. This is useful when I am animating a view to another view or doing something where going into or out of full screen mode will mess stuff up. Sort of like locking down a window from being resized.
The answer to this is posted below.
For anyone interested here are some methods you can categorize or use as is. I spent some time looking for how to do this and thought it can help someone else out:
This one will tell you if you are or are not in full screen mode:
#implementation MyWindow
- (void) setStyleMask:(NSUInteger)styleMask {
MyWindowController *wndController = (MyWindowController *)self.windowController;
wndController.fullScreenMode = (styleMask & NSFullScreenWindowMask);
[super setStyleMask:styleMask];
}
#end
I am setting a property in my window controller.
For completeness here is what the category on NSWindow would look like:
#implementation NSWindow (CategoryNSWindow)
#pragma mark - Full Screen Mode:
- (BOOL) inFullScreenMode {
return (self.styleMask & NSFullScreenWindowMask);
}
#end
These two methods will enable / disable the ability to go into or out of full screen mode:
- (void) enableFullScreen {
NSWindowCollectionBehavior behavior = [self.window collectionBehavior];
behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
[self.window setCollectionBehavior:behavior];
}
- (void) disableFullScreen {
NSWindowCollectionBehavior behavior = [self.window collectionBehavior];
behavior ^= NSWindowCollectionBehaviorFullScreenPrimary;
[self.window setCollectionBehavior:behavior];
}
Rename methods as you please.
There are two events of NSWindowDelegate
DidWindowEnterFullScreen
DidWindowExitFullScreen
which help you solve your problem.
The two events of NSWindowDelegate are:
– windowDidEnterFullScreen:
– windowDidExitFullScreen: