My app stop in AppDelegate - ios

My app stop in AppDelegate.
I am making an app which can access camera and photo library and I can upload photos in my app.
I run my app in my real iPhone from Xcode,but when I put camera access button & photo library button, my app stopped in a part AppDelegate.swift
class AppDelegate: UIResponder, UIApplicationDelegate {
and could not move.
In Cornroller,I wrote
import UIKit
class KenshinSendController:UIViewController,
UINavigationControllerDelegate,UIImagePickerControllerDelegate{
let ButtonCamera = 0
let ButtomRead = 1
let ButtonWrite = 2
var imageView:UIImageView = UIImageView()
var btnCamera:UIButton = UIButton(type: .custom)
var btnRead:UIButton = UIButton(type: .custom)
var btnWrite:UIButton = UIButton(type: .custom)
override func viewDidLoad() {
super.viewDidLoad()
imageView.frame = CGRect(x: 150, y: 100, width: 200, height: 200)
imageView.contentMode = .scaleAspectFit
view.addSubview(imageView)
btnCamera.frame = CGRect(x: 0, y: 100, width: 100, height: 100)
btnCamera.setTitle("Camera", for: .normal)
btnCamera.tag = ButtonCamera
btnCamera.addTarget(self, action: #selector(self.onClick(sender:)), for: .touchUpInside)
btnCamera.backgroundColor = UIColor.green
self.view.addSubview(btnCamera)
btnRead.frame = CGRect(x: 0, y: 200, width: 100, height: 100)
btnRead.setTitle("Read", for: .normal)
btnRead.tag = ButtomRead
btnRead.addTarget(self, action: #selector(self.onClick(sender:)), for: .touchUpInside)
btnRead.backgroundColor = UIColor.red
self.view.addSubview(btnRead)
btnWrite.frame = CGRect(x: 0, y: 300, width: 100, height: 100)
btnWrite.setTitle("Write", for: .normal)
btnWrite.tag = ButtonWrite
btnWrite.addTarget(self, action: #selector(self.onClick(sender:)), for: .touchUpInside)
btnWrite.backgroundColor = UIColor.blue
self.view.addSubview(btnWrite)
}
//ボタンクリック時に呼ばれる
#IBAction func ButtonCamera(_ sender: Any) {
}
#IBAction func ButtonRead(_ sender: Any) {
}
func onClick(sender:UIButton){
if sender.tag == ButtonCamera {
openPicker(sourceType: UIImagePickerControllerSourceType.camera)
}else if sender.tag == ButtomRead {
openPicker(sourceType: UIImagePickerControllerSourceType.photoLibrary)
}
}
//アラートの表示
func showAlert(title: String?, text: String?) {
let alert = UIAlertController(title: title, message: text, preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
present(alert, animated: true, completion: nil)
}
func openPicker(sourceType:UIImagePickerControllerSourceType){
if !UIImagePickerController.isSourceTypeAvailable(sourceType){
showAlert(title: nil, text: "利用できません")
return
}
let picker = UIImagePickerController()
picker.sourceType = sourceType
picker.delegate = self
present(picker, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let image = info[UIImagePickerControllerOriginalImage]as! UIImage
imageView.image = image
picker.presentingViewController?.dismiss(animated: true,completion:nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.presentingViewController?.dismiss(animated: true, completion: nil)
}
}
Identity Inspector is like
and AppDelegate.swift is like
import UIKit
import Alamofire
#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:.
}
}
Info.plist is like
<plist version="1.0">
<dict>
<key>UILaunchStoryboardName</key>
<string></string>
<key>CFBundleGetInfoString</key>
<string></string>
<key>NSPhotoLibraryUsageDescription</key>
<string>フォトライブラリの使用許可をお願いします</string>
<key>CFBundleDisplayName</key>
<string></string>
<key>NSCameraUsageDescription</key>
<string>カメラの使用許可をお願いします</string>
<key>LSApplicationCategoryType</key>
<string></string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
Error message is like Thread 1:signal SIGABRT
I used TabBarController,it is like
Connection Inspector is like

You need to give photo and camera access in info.plist file.
Privacy - Camera Usage Description
Privacy - Photo Library Usage Description

The following answers about iOS 10 will only affect the app's review process and will build and run without errors, so adding these will change nothing in a sense of the app's ability to work:
Privacy - Camera Usage Description: purpose of your app using camera
Privacy - Photo Library Usage Description: purpose of your app using Photo
The issue you are experiencing is usually due to a broken reference your storyboard. You may have changed an outlet name or an IBAction method.
You can check this by selecting the view controller in the storyboard and looking for a ! next to any references. If there is a !, click the X to delete the reference.
See attached image (look at down arrow)
You can also look in the code for an empty circle next to your outlets or actions.

I tested your code, and it's perfect, there is no error in your code.
It seems, you have a wrong link with Interface Builder element in your storyboard. Reason for this kind of error is, wrong link (attachment) of interface builder in storyboard with your view controller.
Please check your initial storyboard & especially initial view controller, its attachment with connection inspector & Identity inspector.
Identity Inspector: Your view controller is properly integrated with current project or not.
Connection inspector: You don't have any wrong link of interface builder.
Share here snapshot of your initial storybaord & view controller also, with identity inspector and connection inspector.
Edit: According to your current snap shot, you may have used Tabbar controller as initial view controller (and two connections are incoming for current view controller you have shared.) but not shared information about tabbar controller here. Share complete snapshot (and source code) of your story board to get exact resolution.

From iOS 10, you have to add privacy descriptions in your info.plist file unless your app will crash when request permission. In your case, you must add:
Privacy - Camera Usage Description : purpose of your app using camera
Privacy - Photo Library Usage Description : purpose of your app using Photo

Related

How to hide game's state when going to background

I am writing a logic puzzle game in SpriteKit that plays on the iPad and is against the clock, and am struggling to hide the puzzle neatly when the app goes into the background.
The issue is that user shouldn't be able to double-tap on the home button and see the full puzzle in the App Switcher, as this would allow them to work through it without the clock running.
This is the solution I have come up with:
In the Singleton GameManager there is a variable that is a SKTexture(), to hold a screenshot texture, and in my AppDelegate I have:
func applicationWillResignActive(_ application: UIApplication) {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "resigning"), object: self)
let tempBackground = UIImageView(image: UIImage(cgImage: GameManager.shared.puzzleImage.cgImage()))
tempBackground.frame = CGRect(x: 0, y: 0, width: 1024, height: 768)
tempBackground.tag = 1000
self.window?.addSubview(tempBackground)
self.window?.bringSubviewToFront(tempBackground)
}
This sends out a notification when it's about to resign the focus, which is picked up by my GameScene, which then creates a screenshot and stores it to the variable in my GameManager. This is then added as a subview in the AppDelegate.
class GameScene: SKScene {
override func didMove(to view: SKView) {
// Layout puzzle here
NotificationCenter.default.addObserver(self, selector: #selector(appToBackground), name: NSNotification.Name(rawValue: "resigning") , object: nil)
}
#objc private func appToBackground() {
// Save state of puzzle and hide it
GameManager.shared.puzzleImage = SKView().texture(from: self)!
}
}
This all works. But not brilliantly. There is a noticeable time-lag between double-tapping and the tempBackground being added - the App Switcher shows the puzzle in detail very briefly and then changes the image to the hidden puzzle.
When the app comes back into focus, the following is called in AppDelegate:
func applicationDidBecomeActive(_ application: UIApplication) {
if let tempBackground = self.window?.viewWithTag(1000) {
tempBackground.removeFromSuperview()
}
}
But when the app returns to focus, the tempBackground is shown, then there is a very brief glimpse of the puzzle in all its detail, before once again showing the hidden puzzle.
I may well have gone about this completely the wrong way, but after reading various archive questions and articles on the internet, this seemed to be way to go.
What I'd like to know is: is there any way that I can have the hidden puzzle shown in the App Switcher immediately and avoid the flash of puzzle detail when returning to the puzzle?
Thanks.
There is no issue in adding subview logic, but the issue is in where are you triggering it, as per apple docs, you should add subview in applicationDidEnterBackground and should remove you subview and prepare your app to display in applicationWillEnterForeground
As I have created Xcode project in Xcode 12, my project has scene delegate, here is the code I used and O/P is shown in gif below
func sceneWillResignActive(_ scene: UIScene) {
guard let view = Bundle.main.loadNibNamed("HiddenView", owner: nil, options: [:])?[0] as? HiddenView else { return }
view.tag = 1000
view.frame = UIApplication.shared.windows[0].frame
UIApplication.shared.windows[0].addSubview(view)
UIApplication.shared.windows[0].bringSubviewToFront(view)
}
func sceneWillEnterForeground(_ scene: UIScene) {
if let tempBackground = UIApplication.shared.windows[0].viewWithTag(1000) {
tempBackground.removeFromSuperview()
}
}
EDIT 1:
As OP has mentioned, that he is not using Scene Delegate I am updating the answer for AppDelegate
func applicationWillResignActive(_ application: UIApplication) {
guard let view = Bundle.main.loadNibNamed("HiddenView", owner: nil, options: [:])?[0] as? HiddenView else { return }
view.tag = 1000
view.frame = UIApplication.shared.windows[0].frame
UIApplication.shared.windows[0].addSubview(view)
UIApplication.shared.windows[0].bringSubviewToFront(view)
}
func applicationDidBecomeActive(_ application: UIApplication) {
if let tempBackground = UIApplication.shared.windows[0].viewWithTag(1000) {
tempBackground.removeFromSuperview()
}
}
I have a solution, although it feels more like a work-around than a proper solution.
The problem is that iOS takes a snapshot of the screen before sending the app into the background and uses this when the app returns to the foreground.
This snapshot can be replaced by using either a predefined view (see #Sandeep's solution) or creating a new snapshot of the screen once the puzzle has been hidden (my original attempted solution).
However, removing this dummy in the applicationDidBecomeActive means that the original snapshot taken by the iOS is shown briefly before updating the screen.
There is a function UIApplication.shared.ignoreSnapshotOnNextApplicationLaunch() which can be entered into the applicationWillResignActive() function, but it doesn't seem to be working all the time - just most of it. In fact, on the Apple Developer's forum there's a comment about how it's inconsistent and a bug was reported. But that was over a year ago and it's still inconsistent.
Instead, in this function add the dummy not to the self.window? directly, but to the view of the rootViewController, using
self.window?.rootViewController!.view.addSubview(dummyImage)
Then don't actually remove this when the app comes back into the foreground. Instead, use Notification to alert GameScene that the app is back in the foreground. This can then run a method which adds a UITapGestureRecognizer to the scene. This in turn can be linked to a method that fades out the dummy image, before removing both it and the UITapGestureRecognizer once it's completed.
Perhaps not the most elegant solution, but it seems to work.

App rotates to landscape and portrait, but won't rotate upside down

When running a simple proof-of-concept iPhone app on my phone (iOS 13.1.2), it doesn't rotate upside down. It will rotate to either of the landscape orientations just fine, but not upside down. One strange thing is that there's also a UITextEffects window whose view controllers get supportedInterfaceOrientations called on them (and they return .allButUpsideDown, which matches with the observed behavior). The project is here, but I'll show all of the code inline.
AppDelegate.swift:
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return .all
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let c = ViewController()
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = c
window?.makeKeyAndVisible()
return true
}
}
ViewController.swift:
import UIKit
class ViewController: UIViewController {
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .all
}
override var shouldAutorotate: Bool {
return true
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .purple
let redView = UIView()
redView.backgroundColor = .red
redView.frame = CGRect(x: 20, y: 20, width: 100, height: 100)
view.addSubview(redView)
}
}
Info.plist (excerpt):
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationPortrait</string>
</array>
This is on purpose, the newer iPhones without Touch Id doesn't have the Upside Down capability. If you run your example on iPhone 8, it rotates as it should.
In https://forums.developer.apple.com/message/268015, an Apple staffer says:
"It is by design. We're getting documentation updated in a future release to reflect that."
And the official Apple documentation says:
The system intersects the view controller's supported orientations with the app's supported orientations (as determined by the Info.plist file or the app delegate's application:supportedInterfaceOrientationsForWindow: method) and the device's supported orientations to determine whether to rotate. For example, the UIInterfaceOrientationPortraitUpsideDown orientation is not supported on iPhone X.
Also, see the Apple Visual Design Orientation:
An app that runs only in portrait mode should rotate its content 180 degrees when the user rotates the device 180 degrees—except on iPhone X, which doesn’t support upside-down portrait mode.

Connecting iOS app with MobFox

I followed the documentation to add MobFox ads in my application. For some reason I am getting the error : Could not connect to the server.
func mobFoxAdDidFailToReceiveAdWithError(_ error:Error!) {
print("MobFoxAdDidFailToReceiveAdWithError: ", error.localizedDescription)
}
And it gives:
MobFoxAdDidFailToReceiveAdWithError: Could not connect to the server.
private var mobfoxAd: MobFoxAd!
override func viewDidLoad() {
super.viewDidLoad()
let rect = CGRect(origin: CGPoint(x: 0, y: 200), size: CGSize(width:320, height: 50))
mobfoxAd = MobFoxAd("fe96717d9875b9da4339ea5367eff1ec", withFrame: rect)
mobfoxAd.delegate = self
mobfoxAd.refresh = adRefresh as NSNumber?
self.view.addSubview(mobfoxAd)
}
In my Info.plist file, I have added.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
I don't seem to find the reason.
Thanks.
Turns out the countries where these services are not provided are not mentioned.
If you face this problem, change to another country with VPN. Ads will appear.

UILabel shows wrong Localized String

I have a problem with localizing a string through the Localizable.stringdict. I did setup different localization for different sizes of a Test string. See Localizable.stringdict:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Test</key>
<dict>
<key>NSStringVariableWidthRuleType</key>
<dict>
<key>20</key>
<string>test</string>
<key>25</key>
<string>test message</string>
<key>50</key>
<string>This is a test message</string>
</dict>
</dict>
</dict>
</plist>
My ViewController looks like the following:
class ViewController: UIViewController {
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let string = NSLocalizedString("Test", comment: "This is a test message") as NSString
let widthFormattedString = string.variantFittingPresentationWidth(50) as String
print(widthFormattedString)
label.text = widthFormattedString
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I would like to assign the localized string to a label. The print in my ViewController is printing "This is a test message", but the view is showing "test message". I don't change the text of the label anywhere else. So I wonder why the wrong message is displayed. Can anyone help?
According to the documentation at writing this answer it states that:
Note
Don't call this method when setting user-visible text for standard UIKit controls, such as UILabel. UIKit provides built-in support for adaptive strings, and automatically selects the string width variant appropriate for the current screen size according to the behavior described below.
which seems to confirm what you experience.
The print out you do yourself is correct because it delivers you the string you requested for the value 50:
The print in my ViewController is printing "This is a test message"
Whereas the UILabel gets a the string by the UIKit standard mechanism and appears as:
but the view is showing "test message"
I conclude that you don't need to do it yourself if you use UIKit controls. This is probably helpful for custom controls or other use cases I'm not aware of.

iOS - Floating Single Button

I need a floating button in my iPhone app, I saw many libraries online like this one: https://cocoapods.org/pods/LiquidFloatingActionButton
But I need it to be just a single button, not a menu - Do you know of any other libraries that do this? Or a way to customise one of the current libraries to do what I need?
Thanks!
import UIKit
final class AppDelegate: NSObject, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {
let buttonDiameter: CGFloat = 44.0
let floatingButton = UIButton(frame: CGRect(x: 0.0, y: 0.0, width: buttonDiameter, height: buttonDiameter))
floatingButton.layer.cornerRadius = buttonDiameter / 2.0
floatingButton.backgroundColor = .redColor()
window?.addSubview(floatingButton)
return true
}
}
This example would add a floating button to the top left corner of your app.
The important aspect of this code is that I am adding the button the UIWindow.
You can access the window of the app from any UIViewController whose view is added to the window via the property window.
To get notifications when a view controller is added to the window you can override the function:
didMoveToWindow()
There is an approach to this by using KCFloating action button and adding a tapGestureRecognizer to a view containing this button.
So, just adding KCFloatingActionButton's pod and adding another view containing it it's possible to have a single floating action button just as androids.
If you require more detail to solve this issue tell me and I'll try to help
Sample image
only copy and paste this code
override func viewDidAppear(_ animated: Bool) {
layoutFAB()
}
func layoutFAB() {
let item = KCFloatingActionButton()
item.buttonColor = UIColor(red: 188/255, green: 46/255, blue: 35/255, alpha: 1)
}
override func viewDidLoad() {
super.viewDidLoad()
let Fab = KCFloatingActionButton()
Fab.addItem("a", icon: UIImage(named: "a")){ item in
print("a")
}
}
self.view.addSubview(Fab)
}

Resources