IBAction func on button not triggering - ios

I have 3 buttons in a VC, all hooked up to IBAction functions. Two of them work fine but the Submit button simply simply won't trigger.
I have made sure User Interaction is enabled. I have also tried adding sender: AnyObject as a parameter and re-hooking up the function to the button but still no luck. I have also cleaned the project. I am very baffled as to what is going on.
Here is how the VC looks:
Hooking the buttons up:
Accessibility of button:
Here is the code for each IBAction func:
#IBAction func captureImage(){
self.saveVideoVar = false
let imageFromSource = UIImagePickerController()
imageFromSource.delegate = self
imageFromSource.allowsEditing = false
//if there is a camera
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera){
imageFromSource.sourceType = UIImagePickerControllerSourceType.Camera
self.presentViewController(imageFromSource, animated: true){}
}
else{
let title = "Error"
let message = "Could not load camera"
let alert = UIAlertController(title: title, message: message, preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Cancel, handler: nil))
presentViewController(alert, animated: true, completion: nil)
}
}
#IBAction func openImageLibrary(){
self.saveVideoVar = false
let imageFromSource = UIImagePickerController()
imageFromSource.delegate = self
imageFromSource.allowsEditing = false
imageFromSource.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
//presents (loads) the library
self.presentViewController(imageFromSource, animated: true){}
}
//code to submit image and video to amazon S3
#IBAction func submitToS3(){
print("x")
if let img : UIImage = imageView.image! as UIImage{
let path = (NSTemporaryDirectory() as NSString).stringByAppendingPathComponent("image.png")
let imageData: NSData = UIImagePNGRepresentation(img)!
imageData.writeToFile(path as String, atomically: true)
// once the image is saved we can use the path to create a local fileurl
let url:NSURL = NSURL(fileURLWithPath: path as String)
nwyt.uploadS3(url)
}
}
Screenshot of control clicking the Submit button:
OH MY GOD! I feel stupid. There was a duplicate screen I had forgotten to delete that looked exactly the same but wasn't the one that was being displayed. I'm going to delete this in an hour. Below was the problem:

Check by setting background colors to the buttons so that you can understand whether any view is over the button or not .

I can see that there is an extra ":" in "submitToS3:", meaning that the function submitToS3 should have an argument, which is not your case.
In order to solve this, just remove the submitToS3 link, and then drag and drop from the Submit button to the yellow icon above in the controller, and link it to the "submitToS3" (you should see it there). When looking back at the Received Actions view, you should not see the ":"

Try this:
//code to submit image and video to amazon S3
#IBAction func submitToS3(sender:UIButton){
print("x")
if let img : UIImage = imageView.image! as UIImage{
let path = (NSTemporaryDirectory() as NSString).stringByAppendingPathComponent("image.png")
let imageData: NSData = UIImagePNGRepresentation(img)!
imageData.writeToFile(path as String, atomically: true)
// once the image is saved we can use the path to create a local fileurl
let url:NSURL = NSURL(fileURLWithPath: path as String)
nwyt.uploadS3(url)
}
}
Seems callback argument was missing. Should work. Finger crossed!!
Please check the enabled property in property inspector!
Check button name!
Create a new button and new method. Try and hook. I had faced this kinda problem. Could be xCode issue if you are using xCode 7.

Related

Xcode Camera: Failed to read exposureBiasesByMode dictionary

I recently got this error with the UIImagePickerController in Xcode Version 12.0.1
[Camera] Failed to read exposureBiasesByMode dictionary: Error Domain=NSCocoaErrorDomain Code=4864 "*** -[NSKeyedUnarchiver _initForReadingFromData:error:throwLegacyExceptions:]: data is NULL" UserInfo={NSDebugDescription=*** -[NSKeyedUnarchiver _initForReadingFromData:error:throwLegacyExceptions:]: data is NULL}
Has anyone else seen this error? How do you fix it?
If you customize your image picker as imagePicker.allowsEditing = true
you have to fetch image using:
if let pickedImage = info[UIImagePickerController.InfoKey.editedImage] as? UIImage {
capturedImage = pickedImage
}
If you instead use imagePicker.allowsEditing = false, use this to pick image:
if let pickedImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
capturedImage = pickedImage
}
If you don't follow this combination, you may get this error.
in my case, I got this bug from trying to use the image data and syncing with Files. Adding this permission in Info.plist made all the difference and made that error go away:
<key>LSSupportsOpeningDocumentsInPlace</key> <true/>
I experienced the same issue. I imported AVKit instead og AVFoundation and tried to present the video in the native recorder view. That gave me an exception telling me to add NSMicrophoneUsageDescription to the info.plist file, and after this, I was able to display the live video in a custom view.
So I believe the issue is with iOS 14 being very picky about permissions, and probably something goes wrong with showing the correct exception when the video is not presented in the native view.
Anyway, this worked for me:
import AVKit
import MobileCoreServices
#IBOutlet weak var videoViewContainer: UIView!
private let imagePickerController = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
initCameraView()
}
func initCameraView() {
// Device setup
imagePickerController.delegate = self
imagePickerController.sourceType = .camera
imagePickerController.mediaTypes = [kUTTypeMovie as String]
imagePickerController.cameraCaptureMode = .video
imagePickerController.cameraDevice = .rear
// UI setup
addChild(imagePickerController)
videoViewContainer.addSubview(imagePickerController.view)
imagePickerController.view.frame = videoViewContainer.bounds
imagePickerController.allowsEditing = false
imagePickerController.showsCameraControls = false
imagePickerController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
}
And then the added description for the NSMicrophoneUsageDescription in the info.plist file :-)
Hope it will work for you as well!
I managed to solve the problem. In fact, it is not directly related to react-native-image-crop-picker. The problem was that I was using react-native-actionsheet to give the user the option to open the camera or the gallery. When I opened the react-native-actionsheet and pressed one of the options, the camera was superimposing the react-native-actionsheet (modal) which generated a conflict, because apparently in IOS it is not possible for one Modal to overlap the other.
So, to solve the problem, I defined a timeout so that it is possible to close the modal before opening the camera.
I got this error when I tried to copy from a URL I couldn't copy. Which was coming from the mediaURL from the UIImagePickerControllerDelegate.
Basically, what I did was to use UISaveVideoAtPathToSavedPhotosAlbum
Like in this example ⤵️
if UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(url.absoluteString) {
UISaveVideoAtPathToSavedPhotosAlbum(url.absoluteString, self, #selector(self.didSaveVideo), nil)
} else {
return /* do something*/
}
#objc private func didSaveVideo(videoPath: String, error: NSError, contextInfo: Any) {}
I found the same error with Xcode 12 & iOS 14 when imagePicker's source type is camera.
But the app is working fine, I could take picture using camera and put it in my collection view cell. Thus, maybe something on Xcode 12 I guess.
#objc func addPerson() {
let picker = UIImagePickerController()
if UIImagePickerController.isSourceTypeAvailable(.camera) {
picker.sourceType = .camera
} else {
fatalError("Camera is not available, please use real device.")
}
picker.allowsEditing = true
picker.delegate = self
present(picker, animated: true)
}
I faced the same error with Xcode 12 & iOS 14.
But in my case, I used ActionSheet to choose camera or photo library before that. So I changed to open camera just after close that ActionSheet, and it works well.
Hope this will be helpful on your issue.
enum MediaOptions: Int {
case Photos
case Camera
}
func selectImage(mediaType: MediaOptions) {
self.mediaOption = mediaType
let iPicker = UIImagePickerController()
iPicker.delegate = self
iPicker.allowsEditing = false
if mediaType == .Camera {
if UIImagePickerController.isSourceTypeAvailable(.camera) {
iPicker.sourceType = .camera
iPicker.allowsEditing = true
}
} else {
iPicker.sourceType = .photoLibrary
}
self.present(iPicker, animated: true, completion: nil)
self.imagePicker = iPicker
}
func choosePhoto() {
let actionSheet = UIAlertController(title: "Choose", message: "", preferredStyle: .actionSheet)
if UIImagePickerController.isSourceTypeAvailable(.camera) {
actionSheet.addAction(UIAlertAction(title: "Camera", style: .default, handler: { (action) -> Void in
actionSheet.dismiss(animated: true) {
self.selectImage(mediaType: .Camera) // Just moved here - inside the dismiss callback
}
}))
}
if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
actionSheet.addAction(UIAlertAction(title: "Photo Library", style: .default, handler: { (action) -> Void in
self.selectImage(mediaType: .Photos)
}))
}
actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(actionSheet, animated: true, completion: nil)
}
In my case, I was missing an Info.plist key for NSCameraUsageDescription.
You should enter the purpose of using camera as the description.
It fixed the crash for me.
Plus, if you don't give the purpose, your app is likely to be rejected.
If like me you have this second message :
[access] This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSCameraUsageDescription key with a string value explaining to the user how the app uses this data.
Then you have to add this to your info.plist dictionary:
<key>NSCameraUsageDescription</key>
<string>so you can choose a photo or take a picture for object detection</string>
It solved the problem for me

Add variable to URL in swift

I am currently developing an app in Xcode with Swift. The general premise of the app is that when the app first loads, the user will be asked to enter a 'mobile linking code' this will essentially be added onto the end of the url as a variable which will serve as their login to the site, the rest of the authentication is done server side. Then when the user logs into the app each time after that, this variable will be auto applied to the URL so that essentially they are always auto logged in.
I have my code setup for the app and the UIAlertController loads with a text field, I am struggling on how to find out how to append the 'mobile linking code' (which the user will type into the text field) to the end of the URL on first load and then also how to append this to the URL that loads each time after that.
The code I have is as follows
At the top of my WebViewController.swift
var webviewurl = "https://mywebsite.co.uk/loginarea.php?link=" (I need to append the mobile link code to the end of that url)
Further down in my code I have my first run dialog, in which I have added a UIAlertController. This will be ran on the very first time opening the app only in which the user will input their 'mobile link code', upon clicking Submit, the webview should be redirected to the url with the data in the text field appended to the end.
if activatefirstrundialog == "true" {
if !user.bool(forKey: "firstrun")
{
user.set("1", forKey: "firstrun")
user.synchronize()
webView.stopLoading()
let ac = UIAlertController(title: "Enter Mobile Link Code", message: "Enter the mobile link code found in your Client Area", preferredStyle: .alert)
ac.addTextField()
let submitAction = UIAlertAction(title: "Submit", style: .default) { [unowned ac] _ in
let answer = ac.textFields![0]
// do something interesting with "answer" here
let url = URL(string: "https://mywebsite.co.uk/loginarea.php?link=")!
self.webView.load(URLRequest(url: url + answer))
}
ac.addAction(submitAction)
present(ac, animated: true)
}
}
}
I would be eternally grateful if someone could help me with this.
TIA
To use the mobileLink between multiple app sessions, you need to save it somewhere after it is entered for the first time by the user.
Let's say we save it in UserDefaults. You can then fetch its value accordingly like so,
if !user.bool(forKey: "firstrun") {
//your code...
let submitAction = UIAlertAction(title: "Submit", style: .default) { [unowned ac] _ in
if let answer = ac.textFields.first?.text {
UserDefaults.standard.set(answer, forKey: "mobileLink")
let url = URL(string: "https://mywebsite.co.uk/loginarea.php?link=\(answer)")!
self.webView.load(URLRequest(url: url))
}
}
//your code...
} else if let mobileLink = UserDefaults.standard.string(forKey: "mobileLink") {
let url = URL(string: "https://mywebsite.co.uk/loginarea.php?link=\(mobileLink)")!
self.webView.load(URLRequest(url: url))
}
Did you mean something like this?
let submitAction = UIAlertAction(title: "Submit", style: .default) { [unowned ac] _ in
let answer = ac.textFields![0]
// do something interesting with "answer" here
if let answerText = answer.text, answerText.count > 0 {
if let percentageEncodedString = "https://mywebsite.co.uk/loginarea.php?link=\(answerText)".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) {
if let url = URL(string:percentageEncodedString) {
self.webView.load(URLRequest(url: url))
} else {
//Handle error here, url is not valid
}
} else {
//Handle error here, url cannot be encoded
}
} else {
//Handle error here, text field's text is nil or text is empty
}
}
You should store this mobile linking code somewhere safe. you can use keychain to store it.
To answer your question, you can concatenate the string and form a URL Like this:
let url = URL(string: "https://mywebsite.co.uk/loginarea.php?link=\(answer)")!
Here answer is a variable.

Issue setting default profile pic in Swift (iOS)

I am new to Swift/iOS development, so this might be a stupid question, but I can't seem to find how to do this correctly.
I am following a youtube guide on how to programmatically code (no storyboard) a login screen in Swift and register a user into a Firebase database. The basic outline of the design are as follows
Once the user clicks the icon of the cat with the crown, the image picker comes up and they can select a profile picture and then register like normal. If the user does not select an image from the picker, the cat with the crown icon gets loaded as the profile picture by default.
What I have been trying to do is make it so a different picture (not the cat, and not shown to the user on the login page) named "nedstark" is set as the default profile picture that is stored in the database.
The program uses LoginController.swift and LoginController + handlers.swift files to make this happen. I tried to add a conditional to the picker where if nothing is selected, the default profile pic is set to a specific default user pic (different than the cat), but it doesn't work.
This is the code that stores the photo and other User info into the Database
let imageName = NSUUID().uuidString
let storageRef = Storage.storage().reference().child("profile_images").child("\(imageName).jpg")
if let profileImage = self.profileImageView.image, let uploadData = UIImageJPEGRepresentation(profileImage, 0.1) {
storageRef.putData(uploadData, metadata: nil, completion: { (metadata, error) in
if let error = error {
print(error)
return
}
if let profileImageUrl = metadata?.downloadURL()?.absoluteString {
let values = ["name": name, "email": email, "profileImageUrl": profileImageUrl]
self.registerUserIntoDatabaseWithUID(uid, values: values as [String : AnyObject])
}
})
}
This is the code where I am trying to set the default profile pic
func handleSelectProfileImageView() {
let picker = UIImagePickerController()
picker.delegate = self
picker.allowsEditing = true
present(picker, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
var selectedImageFromPicker: UIImage?
if let editedImage = info["UIImagePickerControllerEditedImage"] as? UIImage {
selectedImageFromPicker = editedImage
} else if let originalImage = info["UIImagePickerControllerOriginalImage"] as? UIImage {
selectedImageFromPicker = originalImage
}
else { //Testing if default profile pic set
selectedImageFromPicker = UIImage(named: "nedstark")
}
if let selectedImage = selectedImageFromPicker {
profileImageView.image = selectedImage
}
else { //Testing if default profile pic set
profileImageView.image = UIImage(named: "nedstark")
}
dismiss(animated: true, completion: nil)
}
I
I know that this is a total noob question, but any help, tips, or pointers is greatly appreciated. Thanks!
You need to handle delegate method of cancel event. UIImagepickercontrolledelegate has another method
imagePickerControllerDidCancel()
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
imageView.image = UIImage(named: "nedstark")
dismiss(animated: true, completion: nil)
}
When you click on cancel button in pickerviewcontroller then didfinishPickingMedia function won't call. That's way your default image is not set when you tap on cancel button.

PerformSegueWithIdentifier not working Swift

I have a tableView on my page and when I press a specific row, my app is supposed to show another page using segue. However when i click on the appropriate row it freezes, and then when I click a different row the segue finally shows up, which is odd. The code used to work for me but for some reason stopped, and I can't identify the issue because the code is identical (at least as far as I can see). Here is a code snippet :
func restClient(client: DBRestClient!, loadedFile destPath: String!, contentType: String!, metadata: DBMetadata!){
let title = "This format is incorrect"
let message = "You can only download file that is in .txt format"
let okText = "OK"
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
let okayButton = UIAlertAction(title: okText, style: UIAlertActionStyle.Cancel, handler: nil)
alert.addAction(okayButton)
if contentType.rangeOfString("text") != nil{
print("this is text")
self.performSegueWithIdentifier("segue", sender: nil)
}
else{
print("this is an error")
presentViewController(alert, animated: true, completion: nil)
return;
}
let documentsDirectoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! NSString
print("The file \(metadata.filename) was downloaded. Content type: \(contentType). The path to it is : \(documentsDirectoryPath)" )
progressBar.hidden = true
let documentsURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let localFilePath = documentsURL.URLByAppendingPathComponent("Documents")
let checkValidation = NSFileManager.defaultManager()
if (checkValidation.fileExistsAtPath(localFilePath.path!))
{
print("FILE AVAILABLE");
}
else
{
print("FILE NOT AVAILABLE");
}
return
}
didDeselectRowAtIndexPath code :
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath){
let selectedFile: DBMetadata = dropboxMetadata.contents[indexPath.row] as! DBMetadata
let documentsDirectoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
let localFilePath = (documentsDirectoryPath as NSString).stringByAppendingPathComponent(selectedFile.filename)
print("The file to download is at: \(selectedFile.path)")
print("The documents directory path to download to is : \(documentsDirectoryPath)")
print("The local file should be: \(localFilePath)")
showProgressBar()
dbRestClient.loadFile(selectedFile.path, intoPath: localFilePath as String)
}
The picture below illustrates when I click on the file.txt row. As you can see it just stays grey and nothing happens, but after that, if I click on another file, say enumrec.pdf, it will show the appropriate page. Would be happy if anyone could point out what i am doing wrong here.
You should use didSelectRowAtIndexPath instead of didDeselectRowAtIndexPath. The latest is often propose first when using autocompletion, it's easy to make the mistake.
It looks like you are performing your seque after your data call which is on a different thread (so your app can carry on when your data call is running). When you change UI you have to run it on the main thread otherwise you can have issues like this. Just wrap your performSegue code in this:
dispatch_async(dispatch_get_main_queue(),{
self.performSegueWithIdentifier("segue", sender: nil)
});
You can read about threads/backgrounds tasks etc here:
https://developer.apple.com/library/mac/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html

Swift: Make an error handler of AVAudioPlayer

I am using AVAudioPlayer for my app, and when the view controller loads the audio plays automatically as the view loads but how do I make a statement if the audio cannot find that file and when it can't find the file I want an alert message to pop up saying the audio cannot be found.
Code:
var euphoriaAudio = try! AVAudioPlayer(contentsOfURL:
NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("Euphoria", ofType: "mp3")!))
Note: This variable declaration is not in any function. It is outside sitting alone in the class which works perfectly fine.
Should do everything you described.
class EuphoriaViewController: UIViewController {
var player: AVAudioPlayer?
private func showAlert(message: String) {
let alert = UIAlertController(title: "Warning",
message: message,
preferredStyle: .Alert)
let ok = UIAlertAction(title: "OK", style: .Default) { action in
// Execute some code upon OK tap here if you'd like
}
alert.addAction(ok)
presentViewController(alert, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
guard let fileURL = NSBundle.mainBundle().URLForResource("Euphoria",withExtension: "mp3") else {
showAlert("Can't find Euphoria.mp3 resource")
return
}
do {
player = try AVAudioPlayer(contentsOfURL: fileURL)
player?.prepareToPlay()
}
catch {
showAlert("Can't load Euphoria.mp3 resource")
}
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
player?.play()
}
}
Next time, try it yourself and post questions like - I did this, but it doesn't work, here's the code, ...
If you don't know how to display alert, ... You should start with Start developing iOS Apps Today, About iOS App Architecture, iOS HIG, ...
Also you should read How do I ask a good question to get your questions answered in the future. So far you have 10 questions, some of them answered, 3 of them with accepted answer, ... Try to ask better ...

Resources