I have implemented alert window with two text fields. And I want to perform some validation: if one of text fields is blank (user did not input any value), application should not allow user to press the "Done" button.
I don't want to show any alerts, just want to not allow user to save blank data.
I have created the function listed below. Added two guards with return. But in this case if user did not input anything, alert just closes and nothing is saved. I don't want alert window to be closed.
How can it be done if it can be? Have not found the answer. I have checked this question, but looks like it's not applicable for me. Appreciate your help!
private func addTable() {
let alert = UIAlertController(title: NSLocalizedString("inputTableParams", comment: ""), message: nil, preferredStyle: .alert)
alert.addTextField(configurationHandler: configureTableNameTextField)
alert.addTextField(configurationHandler: configureTableCapacityTextField)
alert.textFields?[0].autocapitalizationType = .sentences
alert.textFields?[1].autocapitalizationType = .sentences
alert.addAction(UIAlertAction(title: NSLocalizedString("alertCancel", comment: ""), style: .cancel, handler: nil))
alert.addAction(UIAlertAction(title: NSLocalizedString("alertDone", comment: ""), style: .default, handler: { (UIAlertAction) in
guard self.tableNameTextField.text != "" else {return}
guard self.tableCapacityTextField.text != "" else {return}
let newTable = Table(tableName: self.tableNameTextField.text!, tableCapacity: Int(self.tableCapacityTextField.text!)!)
let result = try? TablesTable.getOrCreateTable(table: newTable)
if result != nil {
self.updateTableView()
}
}))
self.present(alert, animated: true, completion: {})
}
It looks like it is not possible to do exactly what I want, so I have implemented another alert window with error.
//MARK: Functions
//Functions for Alert window for adding table
private func configureTableNameTextField (textField: UITextField!) {
textField.placeholder = NSLocalizedString("tableName", comment: "")
textField.keyboardType = .default
tableNameTextField = textField
}
private func configureTableCapacityTextField (textField: UITextField!) {
textField.placeholder = NSLocalizedString("tableCapacity", comment: "")
textField.keyboardType = .numberPad
tableCapacityTextField = textField
}
private func showAlertParamsNotFilledProperly() {
let alertNoCanDo = UIAlertController(title: NSLocalizedString("alertNoCanDo", comment: ""), message: NSLocalizedString("paramsNotFilledProperly", comment: ""), preferredStyle: .alert)
alertNoCanDo.addAction(UIAlertAction(title: NSLocalizedString("alertDone", comment: ""), style: .cancel, handler: nil))
self.present(alertNoCanDo, animated: true, completion: {})
}
private func showAlertUnableToSave() {
let alertNoCanDo = UIAlertController(title: NSLocalizedString("alertUnableToSaveData", comment: ""), message: NSLocalizedString("checkInputParameters", comment: ""), preferredStyle: .alert)
alertNoCanDo.addAction(UIAlertAction(title: NSLocalizedString("alertDone", comment: ""), style: .cancel, handler: nil))
self.present(alertNoCanDo, animated: true, completion: {})
}
//Functions for managing tables
private func addTable() {
let alert = UIAlertController(title: NSLocalizedString("inputTableParams", comment: ""), message: nil, preferredStyle: .alert)
alert.addTextField(configurationHandler: configureTableNameTextField)
alert.addTextField(configurationHandler: configureTableCapacityTextField)
alert.textFields?[0].autocapitalizationType = .sentences
alert.textFields?[1].autocapitalizationType = .sentences
alert.addAction(UIAlertAction(title: NSLocalizedString("alertCancel", comment: ""), style: .cancel, handler: nil))
alert.addAction(UIAlertAction(title: NSLocalizedString("alertDone", comment: ""), style: .default, handler: { (UIAlertAction) in
if self.tableNameTextField.text == "" || self.tableCapacityTextField.text == "" {
self.showAlertParamsNotFilledProperly()
return
}
if let number = NumberFormatter().number(from: self.tableCapacityTextField.text!) {
let capacity = Int(number)
let newTable = Table(tableName: self.tableNameTextField.text!, tableCapacity: capacity)
let result = try? TablesTable.getOrCreateTable(table: newTable)
if result != nil {
self.updateTableView()
}
} else {
self.showAlertParamsNotFilledProperly()
return
}
}))
self.present(alert, animated: true, completion: {})
}
Related
Playing Vimeo videos on the web displays close captioning controls like this.
How do I display similar controls on iOS with the Vimeo/PlayerKit?
I've looked high and low but found no documentation on the player kit at all.
Since no one else has jumped up with an answer, this is what I've done. Documentation for text tracks in Vimeo/PlayerKit is found in the files Player.swift and RegularPlayer.swift.
From that I constructed a UIButton subclass, CloseCaptionButton, that I display on the video as it plays and allows users to switch tracks.
// A UIAlertAction subclass to pass language code to selected action.
class TaggedAlertAction: UIAlertAction {
var languageCode: String?
public convenience init(title: String?, languageCode: String?, style: UIAlertAction.Style, handler: ((UIAlertAction) -> Void)? = nil) {
self.init(title: title, style: style, handler: handler)
self.languageCode = languageCode
}
}
class CloseCaptionButton: UIButton {
var languages: [PlayerKit.TextTrackMetadata]?
func handleTapFrom(vc: UIViewController, videoPlayer: RegularPlayer) {
guard let languages = languages else { return print("NIL LANGUAGES, Couldn't open language picker") }
let alert = UIAlertController(title: "Pick Captions Language", message: nil, preferredStyle: .actionSheet)
// Create an action item in alert for each language.
languages.forEach({ (textTrack) in
let languageCode = textTrack.language
let name = textTrack.title
alert.addAction(TaggedAlertAction(title: name, languageCode: languageCode, style: .default) { action in
let identifier = (action as! TaggedAlertAction).languageCode
self.selectTrackFor(identifier, videoPlayer: videoPlayer)
})
})
// Last action item allows user to turn off captions (or cancel).
alert.addAction(UIAlertAction(title: "Turn Off Captions", style: .default) { _ in
videoPlayer.select(nil)
})
alert.popoverPresentationController?.sourceView = vc.view
vc.present(alert, animated: true)
}
func selectTrackFor(_ languageCode: String?, videoPlayer: RegularPlayer) {
guard let languageCode = languageCode else { return print("NIL IDENTIFIER") }
let matches = videoPlayer.availableTextTracks.filter({ (track) -> Bool in
return track.language == languageCode
})
guard let match = matches.first else {
return print("No match for language: \(languageCode)")
}
videoPlayer.select(match)
}
// Configure with player.availableTextTracks
func configure(_ tracks: [PlayerKit.TextTrackMetadata]) {
languages = Languages(trackMetadata: tracks)
}
}
// How to use
closeCaptionButton.configure(videoPlayer.availableTextTracks)
#IBAction func ccButtonTapped(_ sender: Any) {
closeCaptionButton.handleTapFrom(vc: self, videoPlayer: videoPlayer)
}
Please enjoy!
I had an issue in AWS where if you create a user account, leave the app, and go back in to confirm it using the code sent to email/SMS, then it will say that the username that you entered must be >1 character and it must follow some pattern. This is a bug in the sample code that amazon posted as well. I am posting here because there was no literature on the topic and I want to post my solution that worked because it was a very frustrating problem.
Here's the error:
Value at 'username' failed to satisfy constraint: Member must have
length greater than or equal to 1; Value at 'username' failed to
satisfy constraint: Member must satisfy regular expression pattern:
[\p{L}\p{M}\p{S}\p{N}\p{P}]+";
Value at 'username' failed to satisfy constraint: Member must have length greater than or equal to 1; Value at 'username' failed to satisfy constraint: Member must satisfy regular expression pattern: [\p{L}\p{M}\p{S}\p{N}\p{P}]+";
When you initially create an account, you are taken to the confirm user storyboard where you have to enter a username and a code. The username however is already entered because you are technically logged in with an unconfirmed account. This is, however, the only time you will be able to log in with an unconfirmed account (unless you find some other work around). Therefore, if one was to segue back to the confirm user controller, they cannot simply type in the username because the code uses the logged in user's username, NOT the username entered. Here's how to fix that problem so you can simply enter the username and code and then confirm the account.
This is my first post in stack so here's my best answer:
in the method...
override func viewDidLoad() {
change...
self.username.text = self.user!.username
to....
if self.user?.username == "" || self.user == nil {
print("user is nil")
} else {
self.username.text = self.user!.username
}
....and insert the following with YOUR poolID and in the #IBAction for your "Confirm" method and YOUR own SEGUE; insert it AFTER you check to see if the code value is empty and BEFORE the "self.user?.confirmSignUp" method...
if self.user?.username == "" || self.user == nil {
// change the poolid to yours
let pool = AWSCognitoIdentityUserPool(fenter code hereorKey: userPoolID)
// change the "username" title to whatever corresponds to the text field identifier you are using
let user = pool.getUser((self.username?.text)!)
user.confirmSignUp(self.code.text!, forceAliasCreation: true).continueWith {[weak self] (task: AWSTask) -> AnyObject? in
guard let strongSelf = self else { return nil }
DispatchQueue.main.async(execute: {
if let error = task.error as? NSError {
let alertController = UIAlertController(title: error.userInfo["__type"] as? String, message: error.userInfo["message"] as? String, preferredStyle: .alert)
let okAction = UIAlertAction(title: "Ok", style: .default, handler: nil)
alertController.addAction(okAction)
strongSelf.present(alertController, animated: true, completion: nil)
} else {
// Change the segue identifier to yours
strongSelf.performSegue(withIdentifier: "confirmedUserSegue", sender:sender)
}
})
return nil
}
}
Hope this helps!
To fix the resend code, do the same thing:
if self.user?.username == "" || self.user == nil {
let pool = AWSCognitoIdentityUserPool(forKey: userPoolID)
let user = pool.getUser((self.username?.text)!)
user.resendConfirmationCode().continueWith {[weak self] (task: AWSTask) -> AnyObject? in
guard let _ = self else { return nil }
DispatchQueue.main.async(execute: {
if let error = task.error as? NSError {
let alertController = UIAlertController(title: error.userInfo["__type"] as? String,
message: error.userInfo["message"] as? String,
preferredStyle: .alert)
let okAction = UIAlertAction(title: "Ok", style: .default, handler: nil)
alertController.addAction(okAction)
self?.present(alertController, animated: true, completion: nil)
} else if let result = task.result {
let alertController = UIAlertController(title: "Code Resent",
message: "Code resent to \(result.codeDeliveryDetails?.destination!)",
preferredStyle: .alert)
let okAction = UIAlertAction(title: "Ok", style: .default, handler: nil)
alertController.addAction(okAction)
self?.present(alertController, animated: true, completion: nil)
}
})
return nil
}
} else
... rest of code from amazon example in else statement...
So I have an image view titled cashOrCredit and have am trying to set it's image programatically but somehow not able to.
First I set the image like this
cell.cashOrCredit.image = UIImage(named: "cash1.png")
and I get an error saying a separator of "," is needed.
Then I tried it this way
var cashImage: UIImage?
cashImage = "cash1.png"
cell.cashOrCredit.image = cashImage
But I get a THREAD 1 EXC BAD INSTRUCTION error.
I can't seem to understand what is going wrong ?
Here is the error
Updated for Swift 3:
use below simple code, to set the image to UIImageView;
class YourViewControllerName: UIViewController {
var mYourImageViewOutlet: UIImageView?
func addImageToUIImageView{
var yourImage: UIImage = UIImage(named: "Birthday_logo")!
mYourImageViewOutlet.image = yourImage
} // call this function where you want to set image.
}
Note: "Birthday_logo" type of image must be present in your Assets.xcassets of your project.
I attached the screenshot if you want any help please refer it.
****// used anywhere you want to add an image to UIImageView. [Here I used one function & in that function, I write a code to set image to UIImageView]****
Enjoy..!
Try this:
cell.cashOrCredit.image = UIImage(named: "cash1")
and check "cash1.png" image is available in Assets.xcassets or not.
If you get solution, then give upvote to my answer.
Delete ".png":
cell.cashOrCredit.image = UIImage(named: "cash1")
You can also set it all programmatically:
let cellImage = UIImageView(frame: CGRect(x: X, y: Y, width: WIDTH, height: HEIGHT))
cellImage.image = UIImage(named: "cash1")
cell.addSubview(cellImage)
Take Outlet of ImageView
#IBOutlet weak var imgProfile: UIImageView!
Go through the following code which contains will be helpful you to pick image or capture image from the camera.
func choosePicker() {
let alertController = UIAlertController(title: "Select Option", message: nil, preferredStyle: (IS_IPAD ? UIAlertControllerStyle.alert : UIAlertControllerStyle.actionSheet))
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: { action -> Void in
})
let gallery = UIAlertAction(title: "From Gallery", style: UIAlertActionStyle.default
, handler: { action -> Void in
self.openPicker(isCamera: false)
})
let camera = UIAlertAction(title: "Take Photo", style: UIAlertActionStyle.default
, handler: { action -> Void in
self.openPicker(isCamera: true)
})
alertController.addAction(gallery)
alertController.addAction(camera)
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion: nil)
}
func openPicker(isCamera : Bool) {
let picker:UIImagePickerController?=UIImagePickerController()
if isCamera {
picker!.sourceType = UIImagePickerControllerSourceType.camera
} else {
picker!.sourceType = UIImagePickerControllerSourceType.photoLibrary
picker!.allowsEditing = true
}
picker?.delegate = self
if UIDevice.current.userInterfaceIdiom == .phone {
self.present(picker!, animated: true, completion: nil)
}
else {
picker!.modalPresentationStyle = .popover
present(picker!, animated: true, completion: nil)//4
picker!.popoverPresentationController?.sourceView = imgProfile
picker!.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection.up
}
}
// MARK: - UIImagePickerControllerDelegate Methods
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
self.imgProfile.image = image
}
picker.dismiss(animated: true, completion: nil);
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
Call choosePicker method wherever you want to call.
Check if cashOrCredit is uiimageview.
Secondly,
cashImage = UIImage(named: "cash1.png")
If that doesnot work, try
cell?. cashOrCredit.image
check if cell is nil?
In the context of Swift code, EXC_BAD_INSTRUCTION usually means you’ve hit a compiler trap, that is, an undefined instruction inserted into the code by the compiler because of a bug detected at runtime. The most common cause of these are:
failure to unwrap an optional — This can be a forced unwrap (!) or an implicit unwrap (accessing an implicitly unwrapped optional that’s nil).
array out of bounds
a failed forced cast (as!), either because the value was a nil optional or because the value was of the wrong type
How do I check if I have pressed on an NSSearchField search button?
search button of NSSearchField
#IBAction func searchTextField(_ sender: NSSearchField) {
if `searchButtonIsClicked` {
//Code if searchButtonIsClicked
return
}
if sender.stringValue != "" {
//My code
}
}
What I need to do instead of searchButtonIsClicked?
Here is the solution.
import Cocoa
class ViewController: NSViewController {
#IBOutlet weak var searchFieldText: NSSearchField!
#IBOutlet weak var labelSearchText: NSTextField!
#IBAction func searchFieldButton(_ sender: NSSearchField) {
if searchFieldText.stringValue != "" {
//My code. For example:
labelSearchText.stringValue = searchFieldText.stringValue
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let cellMenu = NSMenu(title: "Search Menu")
var item: NSMenuItem!
item = NSMenuItem(title: "Clear", action: nil, keyEquivalent: "")
item.tag = Int(NSSearchFieldClearRecentsMenuItemTag)
cellMenu.insertItem(item, at: 0)
item = NSMenuItem.separator()
item.tag = Int(NSSearchFieldRecentsTitleMenuItemTag)
cellMenu.insertItem(item, at: 1)
item = NSMenuItem(title: "Recent Searches", action: nil, keyEquivalent: "")
item.tag = Int(NSSearchFieldRecentsTitleMenuItemTag)
cellMenu.insertItem(item, at: 2)
item = NSMenuItem(title: "Recents", action: nil, keyEquivalent: "")
item.tag = Int(NSSearchFieldRecentsMenuItemTag)
cellMenu.insertItem(item, at: 3)
searchFieldText.searchMenuTemplate = cellMenu
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
}
Thank you for your help.
I think this demo can resolve your question.
Swift Code is below:
if let cell = searchField.cell as? NSSearchFieldCell {
let searchButtonCell: NSButtonCell = cell.searchButtonCell!
let cacelButtonCell: NSButtonCell = cell.cancelButtonCell!
searchButtonCell.target = self
cacelButtonCell.target = self
searchButtonCell.action = #selector(clickSearchButton(_:))
cacelButtonCell.action = #selector(clickCacelButton(_:))
}
This is the second and last section I am battling with converting Swift 2 to Swift 3
The old working code was
func calculateSegmentDirections(index: Int,
time: NSTimeInterval, routes: [MKRoute]) {
let request: MKDirectionsRequest = MKDirectionsRequest()
request.source = locationArray[index].mapItem
request.destination = locationArray[index+1].mapItem
request.requestsAlternateRoutes = true
request.transportType = .Automobile
let directions = MKDirections(request: request)
directions.calculateDirectionsWithCompletionHandler ({
(response: MKDirectionsResponse?, error: NSError?) in
if let routeResponse = response?.routes {
let quickestRouteForSegment: MKRoute =
routeResponse.sort({$0.expectedTravelTime <
$1.expectedTravelTime})[0]
var timeVar = time
var routesVar = routes
routesVar.append(quickestRouteForSegment)
timeVar += quickestRouteForSegment.expectedTravelTime
if index+2 < self.locationArray.count {
self.calculateSegmentDirections(index+1, time: timeVar, routes: routesVar)
} else {
self.showRoute(routesVar, time: timeVar)
self.hideActivityIndicator()
}
} else if let _ = error {
let alert = UIAlertController(title: nil,
message: "Directions not available.", preferredStyle: .Alert)
let okButton = UIAlertAction(title: "OK",
style: .Cancel) { (alert) -> Void in
self.navigationController?.popViewControllerAnimated(true)
}
alert.addAction(okButton)
self.presentViewController(alert, animated: true,
completion: nil)
}
})
}
The converted code is
func calculateSegmentDirections(index: Int,
time: NSTimeInterval, routes: [MKRoute]) {
let request: MKDirectionsRequest = MKDirectionsRequest()
request.source = locationArray[index].mapItem
request.destination = locationArray[index+1].mapItem
request.requestsAlternateRoutes = true
request.transportType = .Automobile
let directions = MKDirections(request: request)
directions.calculateDirectionsWithCompletionHandler ({
(response: MKDirectionsResponse?, error: NSError?) in
if let routeResponse = response?.routes {
let quickestRouteForSegment: MKRoute =
routeResponse.sort({$0.expectedTravelTime <
$1.expectedTravelTime})[0]
var timeVar = time
var routesVar = routes
routesVar.append(quickestRouteForSegment)
timeVar += quickestRouteForSegment.expectedTravelTime
if index+2 < self.locationArray.count {
self.calculateSegmentDirections(index+1, time: timeVar, routes: routesVar)
} else {
self.showRoute(routesVar, time: timeVar)
self.hideActivityIndicator()
}
} else if let _ = error {
let alert = UIAlertController(title: nil,
message: "Directions not available.", preferredStyle: .Alert)
let okButton = UIAlertAction(title: "OK",
style: .Cancel) { (alert) -> Void in
self.navigationController?.popViewControllerAnimated(true)
}
alert.addAction(okButton)
self.presentViewController(alert, animated: true,
completion: nil)
}
})
}
It throws an error on the line
directions.calculateDirectionsWithCompletionHandler ({
The error is
Cannot convert value of type '(MKDirectionsResponse?, NSError?) -> ()' to expected argument type 'MKDirectionsHandler' (aka '(Optional, Optional) -> ()')
If anyone can help me I would be very thankful!!
NSError was renamed to Error in Swift 3.0 This may fix your issue.
This code compiles for me:
func calculateSegmentDirections(index: Int,
time: TimeInterval, routes: [MKRoute]) {
let request: MKDirectionsRequest = MKDirectionsRequest()
request.source = locationArray[index].mapItem
request.destination = locationArray[index+1].mapItem
request.requestsAlternateRoutes = true
request.transportType = .automobile
let directions = MKDirections(request: request)
directions.calculate (completionHandler: {
(response: MKDirectionsResponse?, error: Error?) in
if let routeResponse = response?.routes {
let quickestRouteForSegment: MKRoute =
routeResponse.sorted(by: {$0.expectedTravelTime <
$1.expectedTravelTime})[0]
var timeVar = time
var routesVar = routes
routesVar.append(quickestRouteForSegment)
timeVar += quickestRouteForSegment.expectedTravelTime
if index+2 < self.locationArray.count {
self.calculateSegmentDirections(index+1, time: timeVar, routes: routesVar)
} else {
self.showRoute(routesVar, time: timeVar)
self.hideActivityIndicator()
}
} else
if let _ = error {
let alert = UIAlertController(title: nil,
message: "Directions not available.", preferredStyle: .alert)
let okButton = UIAlertAction(title: "OK",
style: .Cancel) { (alert) -> Void in
self.navigationController?.popViewControllerAnimated(true)
}
alert.addAction(okButton)
self.presentViewController(alert, animated: true,
completion: nil)
}
})
}