Open iCloud Pics in my app - objective-c

I have to show all the iCloud picture in my app. So i have to use those photos for further actions.
Is there any framework which i have use to implement the iCloud functionality.
I have checked the various codes and tuts but not able to get the images form the iCloud.

You should use Photos Framework to get access to photos on iCloud. Photos Framework also support photo editing.
For more details you can follow this link - Photos Framework

Perhaps what you are looking for is the UIImagePickerControllerDelegate.
Make your class to inherit UIImagePickerControllerDelegate;
Create a function to pick image from library or camera, initialize a pickerController constant, set delegate to self, get pickerController source type, from camera or library, set allowsEditing to true and present view controller.
Check the code below:
class YourClass: UIViewController, UIImagePickerControllerDelegate {
...
#IBAction func picImage(sender: UIButton) {
let pickerController = UIImagePickerController()
pickerController.delegate = self
pickerController.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
pickerController.allowsEditing = true
self.presentViewController(pickerController, animated: true, completion: nil)
// before user finish picking image, another func has to run, imagePickerController.
}
// After user pick the image, this method will dismiss active view controller.
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
self.dismissViewControllerAnimated(true, completion: nil)
}
}
This is well understood when watching the link tutorial about CoreData, the video is a bit long but worth your time.
My thanks to Jason Rybka, https://www.youtube.com/watch?v=1kCKlv1npw0.
Works for Swift 2.1 / iOS 9.2.
Good luck.

Related

Stop app going to background when swiping up from bottom edge on iPhone X iOS 12

My game is going into background mode when performing a swipe from the bottom edge of the screen on iPhone X iOS 12.
As per Apple documentation overriding preferredScreenEdgesDeferringSystemGestures and calling setNeedsUpdateOfScreenEdgesDeferringSystemGestures should stop the app from going to background but this is's not working on iOS 12.
I am using Unity3D and the editor has the Defer system gestures on edges option , which is implemented as per apple documentation, but also does not work.
I am compiling the project in Xcode 10.
Does anyone else have this problem and do you have a fix?
PS: I am testing this in an empty single view iOS project, the only added code is the following:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear: animated];
[self setNeedsUpdateOfHomeIndicatorAutoHidden];
[self setNeedsUpdateOfScreenEdgesDeferringSystemGestures];
}
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures
{
return UIRectEdgeAll;
}
- (BOOL)prefersHomeIndicatorAutoHidden
{
return YES;
}
Update: Turns out that if I use a swift implementation it works. Too bad I cannot do this for the Unity3D 2017 generated project.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 11.0, *){
setNeedsUpdateOfScreenEdgesDeferringSystemGestures()
}
}
override var preferredScreenEdgesDeferringSystemGestures: UIRectEdge{
return [.all];
}
}
New Update: In Unity 2019 it works by unchecking "Status Bar Hidden" in Project Stttings\Resolution and presentation and making sure you check at least one edge in Poject Settings\Other Settings\Defer system gestures on edges
Removing prefersHomeIndicatorAutoHidden makes it work in Objective C also.
This is the working example implementation, for anyone having the same problem:
- (void)viewDidLoad {
[super viewDidLoad];
if (#available(iOS 11.0, *)) {
[self setNeedsUpdateOfScreenEdgesDeferringSystemGestures];
}
}
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures
{
return UIRectEdgeAll;
}
And for those who, like me, are using Unity3d just delete the following method from UnityViewControllerBase+iOS.mm in the generated Xcode project:
- (BOOL)prefersHomeIndicatorAutoHidden
{
return YES;
}
As per the apple documentation, preferredScreenEdgesDeferringSystemGestures doesn't stop the app from going to background, it just gives your gesture precedence over system gesture.
However, if you try to do it successively a second time, the system gesture would work. You can easily verify this by comparing with other apps.
By default the line at the bottom which helps in swiping up is black in colour and the swipe up gesture would work instantly if you do not override this method. But in your app, the line will look gray'ed out initially. If you do a swipe up, it will become black again and if you swipe up a second time, the system gesture will work.
I am putting this as an answer because of limited characters for commenting.
For Swift the answer is to override the instance property like so within your UIViewController.
override var preferredScreenEdgesDeferringSystemGestures: UIRectEdge {
get { .all }
}
for example.

2 app delegates, swift and objective-c

So, I have an app mixed with objective-c and swift, (originally objective-c) And I need to figure out how to have 2 app delegates (one for swift, and the other for objective-c). I've done some research, but found nothing. Please help!
EDIT:
So, I succesfully switched, but now in my delegate, i have this code:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let splitViewController = window!.rootViewController as! UISplitViewController
let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController
navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
splitViewController.delegate = self
return true
}
But, splitViewController isn't the first vc, so how would I go around fixing it? (I don't know swift very well)
You only need one delegate, do it in Swift. If you create a new app Xcode will use some default code, which as of 8.3.1 is the following:
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
To answer the comment: it doesn't mess up your code. Remove previous Objective C delegate if needed.

Attempt to present UITabBarController whose view is not in the view hierarchy - Firebase, Swift

I'm working on the login system for an app, and when a user registers, I would like it to go straight "into" the app. Meaning, not back to the login screen, and then redirected "into" the app, or prompted to then login after registering. The desired outcome is working with the following code:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//The disallowed character set is the inverse of the allowed characters
disallowedUsernameCharacters = allowedUsernameCharacters.invertedSet
//Set the delegates
confirmPassTextField.delegate = self
passwordTextField.delegate = self
usernameTextField.delegate = self
emailTextField.delegate = self
//Observe authentication events, if the authentication is successful, perform the segue
ref.observeAuthEventWithBlock { (authData) -> Void in
if authData != nil {
//Use standard defaults
let prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
//Store the uid
prefs.setObject(authData.uid as String, forKey: "UID")
self.performSegueWithIdentifier(self.successfulSignUp, sender: nil)
}
}
}
In which if the user registers, and is authenticated, it will perform the segue to the UITabBarController which contains 5 tabs/views for the app itself. This works fine, but I am given the Warning: Attempt to present on whose view is not in the window hierarchy!
From doing some research, this seems to be a fairly common warning that people get. However, I would like to fix it so that all portions of the app will behave as expected. I found that some people recommended putting the code portion:
//Observe authentication events, if the authentication is successful, perform the segue
ref.observeAuthEventWithBlock { (authData) -> Void in
if authData != nil {
//Use standard defaults
let prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
//Store the uid
prefs.setObject(authData.uid as String, forKey: "UID")
self.performSegueWithIdentifier(self.successfulSignUp, sender: nil)
}
}
Inside of the viewWillAppear method because of the current view potentially not being on the hierarchy at the time the segue is called, but I don't think that is the fix here, because it's not being called immediately, only on authentication events - also I don't want to put it here because my understanding is that this method is called frequently depending on events.
I also found that some people were executing it on a different thread with something along the lines of:
dispatch_async(dispatch_get_main_queue(), {
self.performSegueWithIdentifier(self.successfulSignUp, sender: nil)
})
But what I am thinking is that, the "register" view controller that is triggering the segue, is not the top most view controller and that's why the error is occurring. Also, I read that a solution is to embed a UINavigationController, if this is the solution...does anyone know any resources on how to do this? If there is a different solution, what would it be? Any help would be great! Cheers.
EDIT:
My Storyboard looks like this:
The entry point is to the UITabBarController, and in the AppDelegate.swift I check to see if the user is logged in by checking a boolean value in the user defaults, if they aren't logged in, I change the rootController to the LoginViewController, in which the user can login, and it will segue to the UITabBarController, or they can register, and on successful registration, it will segue to the UITabBarController - it is here that I'm getting the warning
I have not figured out why, and once I do I will update the answer, but to resolve this i put the line self.performSegueWithIdentifier(self.LoginToFeed, sender: nil)
into a seperate function
func callSegue() {
self.performSegueWithIdentifier(self.LoginToFeed, sender: nil)
}
and call the function from the block and the warning no longer appears

Autolayout is not working with NSSplitView and NSPageController with Storyboard. Is this Apple Bug?

I just created a empty project on github --> here <-- to demonstrate the problem (Done in objective-c)
The project is a simple storyboard project. An NSWindowController loads an NSPageController which loads a NSSplitView containing 3 panes. There is no code in the sample project, except the code to load the screens. When the project runs, it looks like this .
How do I get the constraints to make the splitView stretch all the way to the ends when the window is resized? The weird thing is, if you Switch the NSWindowController's contentController from the NSPageController to the NSSplitViewController, then every thing works as expected. Is this Apple Bug? I would appreciate any answer swift/objectivec please. I've tried but nothing works.
[EDIT] - Based on the answer below and further researching (contacted Apple), it appears that NSPageViewController does not use autolayout constraints but relies on autoresizing mask and frame setting on its children views.
So when the page controller creates its view controllers, we should set this:
-(NSViewController *)pageController:(NSPageController *)pageController viewControllerForIdentifier:(NSString *)identifier {
NSViewController *viewController = [self.storyboard instantiateControllerWithIdentifier:identifier];
[viewController.view setAutoresizingMask:(NSViewWidthSizable|NSViewHeightSizable)];
return viewController;
}
With this, the problem is fixed. I wish as an update in future, this control works with Autolayout constraints as it seems more natural.
I had many problems with NSPageController. I found that the solution is to not use auto layout with it.
Try to use the NSAutoresizingMaskOptions on your NSSplitView.
First, remove all constraints inside the NSPageController.
Then:
splitView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
splitView.frame = pageController.view.bounds;
or
splitView.autoresizingMask = [.ViewWidthSizable, .ViewHeightSizable]
splitView.frame = pageController.view.bounds
EDIT
Made a project based on yours here
I also got same issue in Pagecontroller:
And solved it by using the given code:
func pageController(_ pageController: NSPageController, viewControllerForIdentifier identifier: String) -> NSViewController {
switch identifier {
case "formController":
let controller = NSStoryboard(name: "Main", bundle:nil).instantiateController(withIdentifier: "formController") as! FormController
controller.view.autoresizingMask = [.height , .width]
return controller
default:
return self.storyboard?.instantiateController(withIdentifier: identifier) as! NSViewController
}
}
func pageController(_ pageController: NSPageController, identifierFor object: Any) -> String {
return String(describing: object)
}
func pageControllerDidEndLiveTransition(_ pageController: NSPageController) {
print(pageController.selectedIndex)
pageController.completeTransition()
pageController.selectedViewController!.view.autoresizingMask = [.height , .width]
}

NSStoryboardSegue sample code (Yosemite Storyboard)

OS X Yosemite introduced NSStoryboardSegue
“A storyboard segue specifies a transition or containment relationship between two scenes in a storyboard…”
Update:
• If I attempt to use a NSStoryboardSegue subclass in a Storyboard with Yosemite., it crashes with SIGABRT.
• If I ignore segues, and manually present a view controller using a specified, custom animator for presentation and dismissal,
func presentViewController(_ viewController: NSViewController,
animator animator: NSViewControllerPresentationAnimator)
it works as expected.
This post provides additional insight: Animate custom presentation of ViewController in OS X Yosemite
Using that as a reference, here's my attempt so far:
class FadeSegue: NSStoryboardSegue {
override func perform() {
super.perform()
sourceController.presentViewController(destinationController as NSViewController,
animator: FadeTransitionAnimator())
}
}
class FadeTransitionAnimator: NSObject, NSViewControllerPresentationAnimator {
func animatePresentationOfViewController(toViewController: NSViewController, fromViewController: NSViewController) {
toViewController.view.wantsLayer = true
toViewController.view.layerContentsRedrawPolicy = .OnSetNeedsDisplay
toViewController.view.alphaValue = 0
fromViewController.view.addSubview(toViewController.view)
toViewController.view.frame = fromViewController.view.frame
NSAnimationContext.runAnimationGroup({ context in
context.duration = 2
toViewController.view.animator().alphaValue = 1
}, completionHandler: nil)
}
func animateDismissalOfViewController(viewController: NSViewController, fromViewController: NSViewController) {
viewController.view.wantsLayer = true
viewController.view.layerContentsRedrawPolicy = .OnSetNeedsDisplay
NSAnimationContext.runAnimationGroup({ (context) -> Void in
context.duration = 2
viewController.view.animator().alphaValue = 0
}, completionHandler: {
viewController.view.removeFromSuperview()
})
}
}
The problem appears to be with the Swift 'subclassing' of NSStoryboardSegue. If you implement the same functionality using Objective-C, everything works as expected. The problem is specifically with your FadeSeque class. The animator object works fine in either Objective-C or Swift.
So this:
class FadeSegue: NSStoryboardSegue {
override func perform() {
super.perform()
sourceController.presentViewController(destinationController as NSViewController,
animator: FadeTransitionAnimator())
}
}
Will work if provided as an Objective-C class:
#interface MyCustomSegue : NSStoryboardSegue
#end
#implementation FadeSegue
- (void)perform {
id animator = [[FadeTransitionAnimator alloc] init];
[self.sourceController presentViewController:self.destinationController
animator:animator];
}
#end
(I don't think you need to call super )
As this doesn't seem to be documented much anywhere, I have made a small project on github to demonstrate:
NSStoryboardSegue transitions from one NSViewController to another in the same Storyboard
NSViewController present: methods to achieve the same affect to a separate Xib-based NSViewController without using a Storyboard Segue
presentViewController:asPopoverRelativeToRect:ofView:preferredEdge:behavior:
presentViewControllerAsSheet:
presentViewControllerAsModalWindow:
presentViewController:animator:
animator and segue objects in Objective-C and Swift
edit
OK I've tracked down the EXC_BAD_ACCESS issue. Looking in the stack trace it seemed to have something to do with (Objective-C) NSString to (Swift) String conversion.
That made wonder about the identifier property of NSStoryboardSegue. This is used when setting up segues in the Storyboard, and is not so useful in Custom segues created in code. However, it turns out that if you set an identifier in the storyboard to any string value, even "", the crash disappears.
The identifier property is an NSString* in Objective-C
#property(readonly, copy) NSString *identifier
and an optional String in Swift:
var identifier: String? { get }
Note the read-only status. You can only set the identifier on initialising the object.
The designator initialiser for NSStoryboardSegue looks like this in Objective-C:
- (instancetype)initWithIdentifier:(NSString *)identifier
source:(id)sourceController
destination:(id)destinationController
and in Swift:
init(identifier identifier: String,
source sourceController: AnyObject,
destination destinationController: AnyObject)
Note the non-optional requirement in the Swift initialiser. Therein lies the problem and the crash. If you don't deliberately set an identifier in the storyboard, the Custom segue's designated initialiser will be called using a nil value for the identifier. Not a problem in Objective-C, but bad news for Swift.
The quick solution is to ensure you set an identifier string in Storyboard. For a more robust solution, it turns out that you can override the designated initialiser in your custom subclass to intercept a nil-valued string. Then you can fill it in with a default value before passing on to super's designated initialiser:
override init(identifier: String?,
source sourceController: AnyObject,
destination destinationController: AnyObject) {
var myIdentifier : String
if identifier == nil {
myIdentifier = ""
} else {
myIdentifier = identifier!
}
super.init(identifier: myIdentifier,
source: sourceController,
destination: destinationController)
}
I have updated the sample project to reflect this solution
The same issue comes to me since I forgot make Identity to the segue.
After that, my segue subclass could worked fine.
Highly recommend you take a look at the Apple documentation. If you dig into it a bit, you'll notice in the perform method, you can override animations and such:
SWIFT
func perform()
OBJECTIVE-C
- (void)perform
"You can override this method in your NSStoryboardSegue subclass to perform custom animation between the starting/containing controller and the ending/contained controller for a storyboard segue. Typically, you would use Core Animation to set up an animation from one set of views to the next. For more complex animations, you might take a snapshot image of the two view hierarchies and manipulate the images instead of the view objects.*
Regardless of how you perform the animation, you are responsible for installing the destination view controller o window controller (and its contained views) in the right place so that it can handle events. Typically, this entails calling one of the presentation methods in the NSViewController class."
What you might do as well is have a look at some of the iOS UIStoryboardSegue examples out there in the wild and you should find they're quite similar.