Swift UIUserInterfaceIdiom error - swift

i use a view only in landscape for iphone 5/6/6 Plus / iPad Mini/iPad and now I would like to integrate the UIUserInterfaceIdiom in my application for use these devices in landscape.
func openGallary()
{
picker!.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
if UIDevice.currentDevice().userInterfaceIdiom == .Phone
{
self.presentViewController(picker!, animated: true, completion: nil)
}
else
{
popover=UIPopoverController(contentViewController: picker!)
popover!.presentPopoverFromRect(btnClickMe.frame, inView: self.view, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
}
}
I'm trying with this code but I get an error UIUserInterfaceIdiomPad

You have to do it like this:
if UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Phone {
// .....
}
you can also create a read-only computed property to return check it as follow:
var iPhone: Bool {
return UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Phone
}
//
var iPad: Bool {
return UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Pad
}
//
if iPhone {
presentViewController(picker!, animated: true, completion: nil)
} else if iPad {
popover=UIPopoverController(contentViewController: picker!)
popover!.presentPopoverFromRect(btnClickMe.frame, inView: self.view, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
} else {
println("Unspecified")
}

Check your orientation settings by clicking on the project file, selecting your target and inspecting the settings in the "General" tab under the heading "Devices". Make sure iPad is enabled. The error also point to the user interface orientation (just below, labeled "Device Orientation"). Check that as well.

Swift 3 version:
//--- for iPhone: ---------
if UIDevice.current.userInterfaceIdiom == UIUserInterfaceIdiom.phone {
// YOUR CODE
}
//--- for iPad: ---------
if UIDevice.current.userInterfaceIdiom == UIUserInterfaceIdiom.pad {
// YOUR CODE
}
//--- for Apple TV: ---------
if UIDevice.current.userInterfaceIdiom == UIUserInterfaceIdiom.tv {
// YOUR CODE
}

Related

How to use UIWindowScene.windows on iOS 15? [duplicate]

This question already has answers here:
How to resolve: 'keyWindow' was deprecated in iOS 13.0
(27 answers)
Closed 1 year ago.
Currently, with iOS 14.6, I can call a function in my app that displays a share sheet using the following code:
func share(link: URL) {
let activityView = UIActivityViewController(activityItems: [link], applicationActivities: nil)
UIApplication.shared.windows.first?.rootViewController?.present(activityView, animated: true, completion: nil)
}
Since iOS 15 beta, Xcode tells me "'windows' was deprecated in iOS 15.0: Use UIWindowScene.windows on a relevant window scene instead". How can I update this so that my share sheet will work properly in this new version? Thanks!
(Tested with iOS 15.2 running on Xcode 13.2.1)
Improving on Rachid's answer, here is a Swiftier version:
extension UIApplication {
var keyWindow: UIWindow? {
// Get connected scenes
return UIApplication.shared.connectedScenes
// Keep only active scenes, onscreen and visible to the user
.filter { $0.activationState == .foregroundActive }
// Keep only the first `UIWindowScene`
.first(where: { $0 is UIWindowScene })
// Get its associated windows
.flatMap({ $0 as? UIWindowScene })?.windows
// Finally, keep only the key window
.first(where: \.isKeyWindow)
}
}
If you want to find the presented UIViewController in the key UIWindow , here is another extension you could find useful:
extension UIApplication {
var keyWindowPresentedController: UIViewController? {
var viewController = self.keyWindow?.rootViewController
// If root `UIViewController` is a `UITabBarController`
if let presentedController = viewController as? UITabBarController {
// Move to selected `UIViewController`
viewController = presentedController.selectedViewController
}
// Go deeper to find the last presented `UIViewController`
while let presentedController = viewController?.presentedViewController {
// If root `UIViewController` is a `UITabBarController`
if let presentedController = presentedController as? UITabBarController {
// Move to selected `UIViewController`
viewController = presentedController.selectedViewController
} else {
// Otherwise, go deeper
viewController = presentedController
}
}
return viewController
}
}
You can put this wherever you want, but I personally added it as an extension to UIViewController.
This allows me to add more useful extensions, like ones to present UIViewControllers more easily for example:
extension UIViewController {
func presentInKeyWindow(animated: Bool = true, completion: (() -> Void)? = nil) {
DispatchQueue.main.async {
UIApplication.shared.keyWindow?.rootViewController?
.present(self, animated: animated, completion: completion)
}
}
func presentInKeyWindowPresentedController(animated: Bool = true, completion: (() -> Void)? = nil) {
DispatchQueue.main.async {
UIApplication.shared.keyWindowPresentedController?
.present(self, animated: animated, completion: completion)
}
}
}

UIActivityViewControllers across iOS8/iOS9 iPhone/iPad

My app features a share button which uses activityViewController on iPhones (iOS8+) and iPads (iOS9+). As iPads only use UIPopoverController on iOS8 and activityViewController on iOS9, I've implemented some conditions which direct each device to the appropriate controller. The problem is, iTunes Connect has shown crashes on iPads using UIPopoverController:
-[UIPopoverPresentationController presentationTransitionWillBegin]
Is the following code sound?
//if iOS9
if #available(iOS 9, *) {
self.presentViewController(activityViewController, animated: true, completion: nil)
}
//if iOS8
else {
//if iPad
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.Pad) {
let popoverCntlr = UIPopoverController(contentViewController: activityViewController)
popoverCntlr.presentPopoverFromRect(CGRectMake(self.view.frame.size.width/2, self.view.frame.size.height/4, 0, 0), inView: self.view, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
}
//if other
else {
self.presentViewController(activityViewController, animated: true, completion: nil)
}
}

Swift. How do I remove the toolbar in an AVPlayerViewController

I'm presenting an AVPlayerViewController with an AVPlayer and are displaying a pre-roll ad in it, but I want to remove the top and button bar, or make the user unable to dismis the ViewController before the ad is done:
How do I do that?
here's my code for my AVPlayerViewController implementation:
let preRollAdPlayer = AVPlayerViewController()
let player = AVPlayer()
preRollAdPlayer.player = player
if #available(iOS 9.0, *) {
preRollAdPlayer.delegate = self
}
preRollAdPlayer.showsPlaybackControls = false
self.view?.window?.rootViewController?.presentViewController(preRollAdPlayer, animated: true, completion: {
self.preRollAdPlayer.playPrerollAdWithCompletionHandler({ (error) -> Void in
if (error != nil) {
NSLog("Error Message: %#", error)
} else {
print("preRoll loaded")
}
self.preRollAdPlayer.dismissViewControllerAnimated(true, completion: {
if (error != nil) {
NSLog("Error Message: %#", error)
}
})
})
})
According to Apple, you should use showsPlaybackControls property:
A Boolean value that indicates whether the player view controller shows playback controls.
Set it to false:
Swift:
yourAvPlayer.showsPlaybackControls = false
Objective C:
[yourAvPlayer setShowsPlaybackControls:FALSE];

What is the right code for the UIPopoverController

What is the right code for the PopoverController in iOS 9 have anywhere the right code for this code?
#IBAction func share(sender: UIBarButtonItem) {
let activityViewController = UIActivityViewController (
activityItems: [(webview.request?.URL!.absoluteString)! as NSString],
applicationActivities: nil)
if UIDevice.currentDevice().userInterfaceIdiom == .Pad {
//iPad
let activityPopover = UIPopoverController(contentViewController: activityViewController)
activityPopover.presentPopoverFromBarButtonItem(self.shareButton, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
}
else
{
//iPhone
presentViewController(activityViewController, animated: true, completion: nil)
}
}
}
Your code is ancient. You should throw all of that away. In iOS 8 and iOS 9, presented controllers adapt. UIActivityViewController is already a popover on iPad, automatically. Just present it and the right thing will happen.
Of course, you will have to supply it with a sourceView and sourceRect or a bar button item source. Otherwise, you'll crash on the iPad. But that's the case for any popover, so you can't be surprised about it.

Sharing button works perfectly on iPhone but crash on iPad

I'm trying to add a button in order to share some sentences in Twitter, Facebook... etc. It all works on all iPhone models but simulator crash with an iPad.
This is my code:
#IBAction func shareButton(sender: AnyObject) {
frase = labelFrases.text!
autor = labelAutores.text!
var myShare = "\(frase) - \(autor)"
let activityVC: UIActivityViewController = UIActivityViewController(activityItems: [myShare], applicationActivities: nil)
self.presentViewController(activityVC, animated: true, completion: nil)
And this is the error:
Terminating app due to uncaught exception 'NSGenericException', reason: 'UIPopoverPresentationController (<_UIAlertControllerActionSheetRegularPresentationController: 0x7c0f9190>) should have a non-nil sourceView or barButtonItem set before the presentation occurs
How should I solve it?
For ipad (iOS > 8.0) you need to set popoverPresentationController:
//check ipad
if (UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Pad)
{
//ios > 8.0
if ( activityVC.respondsToSelector(Selector("popoverPresentationController"))){
activityVC.popoverPresentationController?.sourceView = super.view
}
}
self.presentViewController(activityVC, animated: true, completion: nil)
More information here:
UIActivityViewController crashing on iOS 8 iPads
Do this instead for Swift 5 to get share button working on both iPad and iPhone:
#IBAction func shareButton(sender: UIButton) { {
let itemToShare = ["Some Text goes here"]
let avc = UIActivityViewController(activityItems: itemToShare, applicationActivities: nil)
//Apps to be excluded sharing to
avc.excludedActivityTypes = [
UIActivityType.print,
UIActivityType.addToReadingList
]
// Check if user is on iPad and present popover
if UIDevice.current.userInterfaceIdiom == .pad {
if avc.responds(to: #selector(getter: UIViewController.popoverPresentationController)) {
avc.popoverPresentationController?.barButtonItem = sender
}
}
// Present share activityView on regular iPhone
self.present(avc, animated: true, completion: nil)
}
Hope this helps!
Slightly adapted version to make it work on any button, iPad and iPhone.
Xcode 13.4.1 (Swift 5.6)
let itemToShare = ["Some Text goes here"]
let avc = UIActivityViewController(activityItems: itemToShare, applicationActivities: nil)
//Apps to be excluded sharing to
avc.excludedActivityTypes = [
UIActivity.ActivityType.print,
UIActivity.ActivityType.addToReadingList
]
// Check if user is on iPad and present popover
if UIDevice.current.userInterfaceIdiom == .pad {
if avc.responds(to: #selector(getter: UIViewController.popoverPresentationController)) {
avc.popoverPresentationController?.sourceView = sender as? UIView
}
}
// Present share activityView on regular iPhone
self.present(avc, animated: true, completion: nil)