Change view when didReceiveRemoteNotification - uiviewcontroller

I am trying to change from the App delegate method to the Master View when I receive a Remote Notification, in order to perform a segue in the Master View to another view, but I am getting an NSInvalidArgumentException
Code in App Delegate when didReceiveRemoteNotification:
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
EmergencyMasterViewController* maincontroller = (EmergencyMasterViewController*)self.window.rootViewController;
[maincontroller alert];
}
Code in MasterView:
-(void)alert
{
[self performSegueWithIdentifier: #"Warning" sender: self];
}
And the error I am getting: [UINavigationController alert]: unrecognized selector

It is because your window rootViewController is actually a UINavigationController instead of your EmergencyMasterViewController. You need to check how you assign the window root view controller in your app delegate didFinishLaunchingWithOptions or something similar.
Try to get the view controller embedded in the navigation controller, for example:
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
NSArray *viewControllers = navigationController.viewControllers
EmergencyMasterViewController *maincontroller = [viewControllers objectAtIndex:0];
It might be safer for the UINavigationController to pop to root view controller first before you try to get the EmergencyMasterViewController, in case the user is already navigating his way through the navigation stack:
[navigationController popToRootViewControllerAnimated:NO];

Related

How do I add a UITextfield that requests a webpage

I am working on turning https://ppyazi.com/viral into a web view to submit to the Apple App Store. I am trying to make a UITextfield that when someone enters their twitter username, it requests https://ppyazi.com/viral/home.php?username=(UsernameHere). Basically, I want the UITextfield to function the same way as the login section on https://ppyazi.com/viral.
You can either add a UIButton with action requesting ppyazi url or you can declare :
textview.delegate = self;
and implement UITextViewDelegate
and use :
func textViewDidEndEditing(_ textView: UITextView) -> Bool {
//Do your Code to request URL
return true
}

Why is dismissing uinavigationcontroller not releasing view controller memory?

Implementing UIDocumentBrowserViewController in an existing app. This vc, in iOS 11 is the root view controller, and tapping a file creates my doc, instantiates my view controller, and presents it inside a UINavigationController. It all works, in that the files display, the proper document opens, the vc displays and works as expected. I had to add a left button to the nav bar to provide a way to close the doc/vc.
When I tap the "Done" button, the view controller closes and returns to the document browser. All of that is good.
The problem is that the view controller's memory isn't releasing (and the domino effect of document memory, etc then not releasing). In the iOS 10 side of things, with a UICollectionViewController embedded in a UINavigationController as the initial vc, but the doc and the display vc identical code for iOS 10 & 11, all memory releases. I've studied How to correctly dismiss a UINavigationController that's presented as a modal? and related posts, tried dozens of alternatives, and am just not seeing what I'm missing. Instruments isn't showing any memory leaks, though I see document objects in memory after dismissing the view controller. The log shows that the vc's viewWillDisappear is being called at the proper time.
I appreciate any insights into why the vc memory isn't being released (deinit() not being called).
Thank you.
#available(iOS 11.0, *)
class DocumentBrowserViewController: UIDocumentBrowserViewController, UIDocumentBrowserViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
allowsDocumentCreation = true
allowsPickingMultipleItems = false
}
// MARK: Document Presentation
func returnToDocumentBrowser(sender: UIBarButtonItem) {
print("returnToDocumentBrowser")
if let controller = self.presentedViewController as? UINavigationController {
controller.dismiss(animated: true, completion: nil)
}
}
func presentDocument(at documentURL: URL) {
print("present document")
let doc = MyDocument(fileURL: documentURL)
doc.open(completionHandler: { (success) in
if (success) {
print("open succeeded")
DispatchQueue.main.async {
let myController = self.storyboard!.instantiateViewController(withIdentifier: "my controller") as! MyViewController
myController.navigationItem.setLeftBarButton(UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.done, target: self, action: #selector(self.returnToDocumentBrowser(sender:))), animated: false)
myController.doc = doc
let navigationController = UINavigationController(rootViewController: myController)
self.present(navigationController, animated: true, completion: nil)
}
} else {
print("open failed")
}
})
}
}
The navigation stack seems at the heart of this. In the iOS 10 version, a collection view controller is the root view controller and is embedded in a navigation controller via storyboard.
In the iOS 11 version, the document browser view controller is the root view controller and cannot be embedded in a navigation controller. When I presented in the original code, my document view controller became the navigation stack's root view controller, and that cannot be popped, for example.
So I figured that maybe the navigation controller needed a different root view controller to mimic the prior behavior as much as possible and require the fewest code changes.
So I changed
let navigationController = UINavigationController(rootViewController: myController)
self.present(navigationController, animated: true, completion: nil)
to
let dummyVC = UIViewController()
let navigationController = UINavigationController(rootViewController: dummyVC)
from.present(navigationController, animated: true, completion: nil)
dummyVC.navigationController?.pushViewController(myController, animated: true)
This nav controller setup added a back button, meaning I didn't have to add a back button, and that handled popping the view controller automatically. As a result, I only needed to dismiss the nav controller, since it wasn't the app's root vc.
Finally, for the comment that the delegate should be declared weak, that's Apple's doing, and I just use it as provided. I'm not sure what affect that's having on things.

Segue not transitioning to next view?

I have been trying to figure this out for well over 3 hours now. After I successfully authorize my login with facebook, when the view tries to transition to the next view, it crashes with sigbart error: [4923:c07] * Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key SegueToScene1.'
This is my segue to scene:
- (IBAction)loginButtonTouchHandler:(id)sender {
// Set permissions required from the facebook user account
NSArray *permissionsArray = #[ #"user_about_me", #"user_relationships", #"user_birthday", #"user_location"];
// Login PFUser using facebook
[PFFacebookUtils logInWithPermissions:permissionsArray block:^(PFUser *user, NSError *error) {
[_activityIndicator stopAnimating]; // Hide loading indicator
if (user.isNew) {
NSLog(#"User with facebook signed up and logged in!");
[self performSegueWithIdentifier: #"SegueToScene1"
sender: self];
} else {
NSLog(#"User with facebook logged in!");
[self performSegueWithIdentifier: #"SegueToScene1"
sender: self];
}}];
[_activityIndicator startAnimating]; // Show loading indicator until login is finished
}
My question is, why does xcode keep refusing the segue?
Edit: I deleted my segue and put a new one "SegueMain", then changed the code to reflect that, but strangely, it still returns the same error with SegueToScene1. How strange is this? There is no trace of that title left...anywhere. Yet, it remains...
I imagine you have something connected in interface builder to perform the SegueToScene1 segue. To find it you could try searching the plain text version of your storyboard or you should probably have an idea of where it would be.

Game Kit with iOS6

I recently tried to authenticate the local user on iOS 6 with the new iOS 6 method, and it returns in the authenticate handler-
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error)
How do I display this view controller? (FYI- GC automatically dismisses the window when completed authenticating the local player)
I'm using storyboard in the project.
Thanks!
Once you set the handler, it will be called at different situations. In those calls, the viewController parameter can be nil or it can actually be an instance GKHostedAuthenticateViewController.
You need to check if the viewController is not nil, and in that case, you can display it as you would do with any other view controller.
Here you have some sample code from the Game Center Programming guide
- (void) authenticateLocalPlayer
{
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error){
if (viewController != nil)
{
[self showAuthenticationDialogWhenReasonable: viewController
}
else if (localPlayer.isAuthenticated)
{
[self authenticatedPlayer: localPlayer];
}
else
{
[self disableGameCenter];
}
}];
}
Check out the GKLocalPlayer Class Reference and the Game Center Programming Guide

Always move to specific uiviewcontroller

I have a IOS app, that uses a network connection, and at times, it looses this network connection, whenever it does, I want the app to move back to a specific UIViewController.. What is the best way to achieve this?
Can I do this from the appDelegate?
Are you using the Reachability class described in the Apple documentation? If not, you should take a look at it. It will give you network status, including whether you are connected to the internet. It has a notification of network status change so you can put an observer in you app delegate or anywhere else you need it to accomplish your objective.
There is a lot of help already available on the web with examples on how to use Reachability, and this one may be something you can start with.
Update
Raachability change notifications can be used to inform your app when the connection is lost or restored. See the notification statement in the code below for the Reachability class;
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
{
#pragma unused (target, flags)
NSCAssert(info != NULL, #"info was NULL in ReachabilityCallback");
NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], #"info was wrong class in ReachabilityCallback");
//We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively
// in case someon uses the Reachablity object in a different thread.
NSAutoreleasePool* myPool = [[NSAutoreleasePool alloc] init];
Reachability* noteObject = (Reachability*) info;
// Post a notification to notify the client that the network reachability changed.
[[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];
[myPool release];
}
For this to work you have to call startNotifier:
- (BOOL) startNotifier
{
BOOL retVal = NO;
SCNetworkReachabilityContext context = {0, self, NULL, NULL, NULL};
if(SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context))
{
if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
{
retVal = YES;
}
}
return retVal;
}