I have a UIViewController with 2 UITextFields and 1 UIImageView (the image is optional)
When I click Save I want to save all values in an array of objects. But the image (selectedImage) is not mandatory.
The issue is with the UIImage because is asking me for an optional value for the UIImage if I don't have an image. And I don't know what to assign because I don't want to have any image in my array if the user did't picked a picture. And I've tried to put a NIL value but is not working.
Here is my code for Model:
import Foundation
import UIKit
class RoadsideDefect {
var vehicleReg: String
var detailsDefect: String
var imagesDefect: [UIImage]?
init(vehicleRegistration: String, detailsOfDefect: String, imagesOfDefects: [UIImage]?) {
self.vehicleReg = vehicleRegistration
self.detailsDefect = detailsOfDefect
self.imagesDefect = imagesOfDefects
}
}
Here is the code in the Controller:
var vehicleReg = ""
var detailsDefect = ""
var imagesDefect: [UIImage]? = [UIImage]()
var roadsideDefect: [RoadsideDefect] = []
//MARK: Save button tapped
#IBAction func saveBtnTapped(_ sender: UIBarButtonItem) {
guard let vehicleRegText = vehicleRegTextfieldOutlet.text, !vehicleRegText.isBlank else {
showAlertWithTitle(title: "Error", message: "Please add vehicle reg number.")
return
}
guard let detailsText = detailsTextfieldOutlet.text, !detailsText.isBlank else {
showAlertWithTitle(title: "Error", message: "Please add some details.")
return
}
let selectedImage: UIImage? = roadsideDefectImageView?.image
vehicleReg = vehicleRegText
detailsDefect = detailsText
// ISSUE HERE
UIImageWriteToSavedPhotosAlbum(selectedImage ?? HowToSetItNilOrEmpty?, self, #selector(self.image(_:didFinishSavingWithError:contextInfo:)), nil)
roadsideDefect.append(RoadsideDefect(vehicleRegistration: vehicleReg, detailsOfDefect: detailsDefect, imagesOfDefects: imagesDefect))
print(roadsideDefect)
}
I marked the issue with a comment.
if let image = selectedImage {
UIImageWriteToSavedPhotosAlbum(image, self, #selector(self.image(_:didFinishSavingWithError:contextInfo:)), nil)
}
You can use optional binding for unwrapping optionals.
guard let imageView = roadsideDefectImageView else { return }
guard let image = imageView.image else { return }
UIImageWriteToSavedPhotosAlbum(image, self, #selector(self.image(_:didFinishSavingWithError:contextInfo:)), nil)
Related
I am new in swift and I am facing problem to show multiple url string image to uiimage
my code is like this
In viewdidLoad
Array = [UIImage (named: "ISDI1")!,UIImage (named: "ISDI2")!,UIImage (named: "ISDI3")!,UIImage (named: "ISDI4")!,UIImage (named: "ISDI5")!]
sliderView.maximumValue = Float(Array.count - 1)
#IBAction func btnPreviousClick(_ sender: Any) {
sliderView.value -= 1
imgView.image = Array[Int(sliderView.value)]
}
#IBAction func btnNextClick(_ sender: Any) {
sliderView.value += 1
imgView.image = Array[Int(sliderView.value)]
}
#IBAction func SliderViewClick(_ sender: UISlider) {
var value = Int(sender.value)
imgView.image = Array[value]
}
Now I am getting url string like this
http://diceapp.in/mailer_isdi_2020/images/4.jpeg , http://diceapp.in/mailer_isdi_2020/images/3.jpeg , http://diceapp.in/mailer_isdi_2020/images/1.jpeg
How can I show this urls in image view ?
I am using this code to convert url to image but it getting crash now
let url = NSURL(string:Image ?? "")
if !(url?.absoluteString == "") {
let data = NSData(contentsOf: url! as URL) //make sure your image in this url does exist, otherwise unwrap in a if let check
imgView.image = UIImage(data: data! as Data)
}
First you need to get the image urls from the string by using this
var imageUrlStrings = "http://diceapp.in/mailer_isdi_2020/images/4.jpeg , http://diceapp.in/mailer_isdi_2020/images/3.jpeg , http://diceapp.in/mailer_isdi_2020/images/1.jpeg"
var imageArr = imageUrlStrings.components(separatedBy: " , ")
The value of imageArr will be like
["http://diceapp.in/mailer_isdi_2020/images/4.jpeg", "http://diceapp.in/mailer_isdi_2020/images/3.jpeg", "http://diceapp.in/mailer_isdi_2020/images/1.jpeg"]
Now you have the individual image URL. Download and show image in individual index.
I'm trying to add two numbers in Swift 5, and I want to add some error checks. I don't want to make it possible for a user to click on the plus button if both of the text fields are not filled in. I tried with the if state below but it did not work.
the whole function:
#IBAction func sum(_ sender: Any) {
let one = input1.text
let oneInt = Int(one!)
let two = input2.text
let twoInt = Int(two!)
let total = oneInt! + twoInt!
label.text = "\(total)"
if(input2.text == nil){
addBtn.isEnabled = false
}
if(input1.text == nil){
addBtn.isEnabled = false
}
}
Try to use guard like this. If your input field does not contain any value that field return blank string and when you try to get integer value from that string it will return nil and your add button will be disable.
#IBAction func sum(_ sender: Any) {
guard let text1 = input1.text, let intValue1 = Int(text1) else {
addBtn.isEnabled = false
return
}
guard let text2 = input2.text, let intValue2 = Int(text2) else {
addBtn.isEnabled = false
return
}
label.text = "\(intValue1 + intValue2)"
}
A nice and simple way is to addTarget to your textFiels. This will enable you to handle the events on the text field. In this scenario we'll use .editingChanged and use a single selector to achieve our goal:
What we'll do : We will listen for when someone types something in the textfield. Whenever a text changed was made, we'll check to see if all the textfields was populated and then if it was we enable the sum button.
A small controller sample :: Make sure to read the comments to understand the code faster
import UIKit
class ViewController: UIViewController {
#IBOutlet var textfield1: UITextField!
#IBOutlet var textfield2: UITextField!
#IBOutlet var sumButton: UIButton!
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
sumButton.isEnabled = false /// Disable the button first thing
[textfield1, textfield2].forEach {
$0.addTarget(self, action: #selector(editingChanged(_:)), for: .editingChanged) /// add targets to handle the events (in your case it listens for the 'editingChanged' event )
}
}
#objc func editingChanged(_ textField: UITextField) {
/// Here we just loop through all our textfields
for each in [textfield1, textfield2] {
if let text = each?.text { /// Just make sure the textfields text is not nil
if text.count < 1 {
// If the textfiels text has no value in, then we keep the button disabled and return
sumButton.isEnabled = false
return
}
} else {
/// Else if the text field's text is nill, then return and keep the button disabled
sumButton.isEnabled = false
return
}
}
sumButton.isEnabled = true /// If the code reaches this point, it means the textfields passed all out checks and the button can be enabled
}
#IBAction func sum(_ sender: Any) {
let one = textfield1.text!
let two = textfield2.text!
guard let oneInt = Int(one), let twoInt = Int(two) else {
print("Whatever was in that text fields, couldn't be converted to an Int")
label.text = "Be sure to add numbers."
return
}
let total = oneInt + twoInt
label.text = "\(total)"
}
}
textfields are not nil but empty strings. so make your comparison like :
if input1.text == "" {
// do your check here
}
Seems like you want to start with addBtn.isEnabled = false then update it whenever the user enters two valid integers into the text fields, i.e. Int(input1.text ?? "") != nil && Int(input2.text ?? "") != nil. You can do this by adding a target to your textfields (input1 and input2) for .editingChanged events. For example, if you're doing this in a UIViewController, you can do this in viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
addBtn.isEnabled = false
input1.addTarget(self, action: #selector(textFieldDidEdit(_:)), for: .editingChanged)
input2.addTarget(self, action: #selector(textFieldDidEdit(_:)), for: .editingChanged)
}
Where textFieldDidEdit(_:) action looks like:
#objc func textFieldDidEdit(_ sender: UITextField) {
addBtn.isEnabled = Int(input1.text ?? "") != nil && Int(input2.text ?? "") != nil
}
Finally your sum function becomes:
#IBAction func sum(_ sender: UIButton) {
guard let oneInt = Int(input1.text ?? ""), let twoInt = Int(input2.text ?? "") else {
return
}
let total = oneInt + twoInt
label.text = "\(total)"
}
As all of the number validation has moved to the textFieldDidEdit(_:) function.
I'm trying to make a choose-your-own adventure game that changes the text of two labels (the user choices) depending on which label the user taps. I figured I would just do a very nested if-else statement rather than bother with trying to implement a binary tree. I know how to attach the gesture recognizer to a label (I think):
let tapped1 = UITapGestureRecognizer(target: self, action: #selector(VCGame.usrChose1))
choice1.isUserInteractionEnabled = true
choice1.addGestureRecognizer(tapped1)
let tapped2 = UITapGestureRecognizer(target: self, action: #selector(VCGame.usrChose2))
choice2.isUserInteractionEnabled = true
choice2.addGestureRecognizer(tapped2)
and I can define what to do when the label is touched in the usrChose1 and usrChose2 functions, however, those functions only work once: the first time the function is chosen and my game has more than just one choice. From there, the labels will just do the same thing if the user touches them.
How would I go about having a condition inside the if-else statement that evaluates to true or false if label1 or label2 is tapped?
Here's the code for usrChoice1 and usrChoice2, for clarification
func usrChose1(sender : UITapGestureRecognizer) {
print("tap 1 working")
choice1.text = "choice1.1"
choice2.text = "choice1.2"
}
func usrChose2(sender : UITapGestureRecognizer) {
print("tap2 working")
choice1.text = "update2.1";
choice2.text = "update2.2"
}
Below image shows my requirement :
According to your requirement, I have tried the following:
I have made a dummy project with two labels inside a view controller
ViewController.swift
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var choice1Label: UILabel!
#IBOutlet weak var choiceLabel2: UILabel!
var tapStart: Bool = false
var levelType1: Level?
var levelType2: Level?
override func viewDidLoad() {
super.viewDidLoad()
let tapped1 = UITapGestureRecognizer(target: self, action: #selector(usrChose1))
choice1Label.isUserInteractionEnabled = true
choice1Label.addGestureRecognizer(tapped1)
let tapped2 = UITapGestureRecognizer(target: self, action: #selector(usrChose2))
choiceLabel2.isUserInteractionEnabled = true
choiceLabel2.addGestureRecognizer(tapped2)
setup()
}
var currentLevel1: Level?
var currentLevel2: Level?
func setup() {
let lb2Child1Child1 = Level(text: "2.1.1", subLevels: nil)
let lb2Child1Child2 = Level(text: "2.1.2", subLevels: nil)
let lb1Child1Child1 = Level(text: "1.1.1", subLevels: nil)
let lb1Child1Child2 = Level(text: "1.1.2", subLevels: nil)
let lb1Child2Child1 = Level(text: "1.2.1", subLevels: nil)
let lb1Child2Child2 = Level(text: "1.2.2", subLevels: nil)
let lb1Child1 = Level(text: "1.1", subLevels: [lb1Child1Child1, lb1Child1Child2])
let lb1Child2 = Level(text: "1.2", subLevels: [lb1Child2Child1, lb1Child2Child2])
let lb2Child1 = Level(text: "2.1", subLevels: [lb2Child1Child1, lb2Child1Child2])
let lb2Child2 = Level(text: "2.2", subLevels: nil)
levelType1 = Level(text: "1", subLevels: [lb1Child1, lb1Child2])
levelType2 = Level(text: "2", subLevels: [lb2Child1, lb2Child2])
choice1Label.text = levelType1!.text ?? ""
choiceLabel2.text = levelType2!.text ?? ""
}
func usrChose1(sender : UITapGestureRecognizer) {
if !tapStart {
currentLevel1 = levelType1
tapStart = true
}
if let subLevelsArray = currentLevel1?.subLevels {
print(subLevelsArray[0].text ?? "")
print(subLevelsArray[1].text ?? "")
choice1Label.text = subLevelsArray[0].text ?? ""
choiceLabel2.text = subLevelsArray[1].text ?? ""
currentLevel1 = subLevelsArray[0]
currentLevel2 = subLevelsArray[1]
}
}
func usrChose2(sender : UITapGestureRecognizer) {
//print("tap2 working")
// choice1Label.text = "update2.1";
//choiceLabel2.text = "update2.2"
if !tapStart {
currentLevel2 = levelType2
tapStart = true
}
if let subLevelsArray = currentLevel2?.subLevels {
print(subLevelsArray[0].text ?? "")
print(subLevelsArray[1].text ?? "")
choice1Label.text = subLevelsArray[0].text ?? ""
choiceLabel2.text = subLevelsArray[1].text ?? ""
currentLevel1 = subLevelsArray[0]
currentLevel2 = subLevelsArray[1]
}
}
}
I have made a class named Level to represent a single level and each level contains sublevels
Level.swift
import UIKit
class Level {
var text: String?
var subLevels: [Level]?
init(text: String, subLevels: [Level]?) {
self.text = text
self.subLevels = subLevels ?? nil
}
}
You have to add UITapGestureRecognizer in UILabel or UIView whatever is container.
Add 2 different Int variables in each functions usrChose1 and usrChose2 respectively, which will be work as a counter.
var i = 0
var j = 0
func usrChose1(_ recognizer: UITapGestureRecognizer) {
i++
print("Total clicked label 1 :::",i)
}
func usrChose2(_ recognizer: UITapGestureRecognizer) {
j++
print("Total clicked label 2 :::",j)
}
I'm using an image slideshow from here:
iconArr = [UIImage(named: "home-min")!,UIImage(named: "category-
min")!,UIImage(named: "settings-min")!,UIImage(named: "contact us-min")!,UIImage(named: "about us-min")!,UIImage(named: "logout")!]
I need to make this array as an image source.
for image in self.iconArr {
let img = image
self.SlideShow.setImageInputs([ImageSource(image: img)])
}
But that is not working, how can I do that?
you should try this way for sure, because you reset inputs in your for-loop
var imageSource: [ImageSource] = []
for image in self.iconArr {
let img = image
imageSource.append(ImageSource(image: img))
}
self.SlideShow.setImageInputs(imageSource)
As sooper stated, can be done this way
let imageSources = self.iconArr.map { ImageSource(image: $0) }
I found a solution from this url [https://stackoverflow.com/a/50461970/5628693][1]
Below is my code working fine :
var imageSDWebImageSrc = [SDWebImageSource]()
#IBOutlet weak var slideshow: ImageSlideshow!
Add below viewDidLoad()
slideshow.backgroundColor = UIColor.white
slideshow.slideshowInterval = 5.0
slideshow.pageControlPosition = PageControlPosition.underScrollView
slideshow.pageControl.currentPageIndicatorTintColor = UIColor.lightGray
slideshow.pageControl.pageIndicatorTintColor = UIColor.black
slideshow.contentScaleMode = UIViewContentMode.scaleAspectFill
// optional way to show activity indicator during image load (skipping the line will show no activity indicator)
slideshow.activityIndicator = DefaultActivityIndicator()
slideshow.currentPageChanged = {
page in
print("current page:", page)
}
let recognizer = UITapGestureRecognizer(target: self, action: #selector(Dashboard.didTap))
slideshow.addGestureRecognizer(recognizer)
} // now add below func
#objc func didTap() {
let fullScreenController = slideshow.presentFullScreenController(from: self)
// set the activity indicator for full screen controller (skipping the line will show no activity indicator)
fullScreenController.slideshow.activityIndicator = DefaultActivityIndicator(style: .white, color: nil)
}
And last step i was getting json data from below alamofire request
Alamofire.request(url, method: .post, parameters: data, encoding: JSONEncoding.default).responseJSON { response in
if(response.value == nil){
}
else {
let json2 = JSON(response.value!)
switch response.result {
case .success:
self.indicator.stopAnimating()
if let details = json2["imgs"].array {
for dItem in details {
let img = dItem["img"].stringValue
let image = SDWebImageSource(urlString: self.imgurl+img)
self.imageSDWebImageSrc.append(image!)
}
self.slideshow.setImageInputs(self.imageSDWebImageSrc)
}
break
case .failure( _):
break
}
}
}
Thanks dude :) happy coding
I'm sure most of you have dealt with forced decompression on a background thread to enhance rendering performance. My question is whether there is a way to check if an image has been decompressed.
It helped me to checked Image has been Decompressed or not by below technique. It is simple code to understand :-
import UIKit
class ViewController: UIViewController {
var compressedImage:NSString?
var decompressedImage:NSString?
override func viewDidLoad() {
super.viewDidLoad()
let image = compressImage()
var imageView = UIImageView(image: image)
//self.view.addSubview(imageView)
let decompressImage = deCompressImage(image: image)
let imageData = Data(UIImagePNGRepresentation(decompressImage)! )
print("***** Size after decompred \(imageData.description) **** ")
imageView = UIImageView(image: decompressImage)
decompressedImage = imageData.description as NSString?
let decompressed = checkImageBeenDecompressed(decompressedImage: decompressedImage!, compressedImage: compressedImage!)
print(decompressed)
//self.view.addSubview(imageView)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func checkImageBeenDecompressed(decompressedImage:NSString , compressedImage:NSString) -> Bool {
let decompressedSize = Int( decompressedImage.getNumFromString()! )
let compressedSize = Int (compressedImage.getNumFromString()! )
if( decompressedSize! > compressedSize! ) {
print("Image has been decompressed")
return true
}
print("Image has not been decompressed")
return false
}
func compressImage() -> UIImage {
let oldImage = UIImage(named: "background.jpg")
var imageData = Data(UIImagePNGRepresentation(oldImage!)! )
print("***** Original Uncompressed Size \(imageData.description) **** ")
imageData = UIImageJPEGRepresentation(oldImage!, 0.025)!
print("***** Compressed Size \(imageData.description) **** ")
compressedImage = imageData.description as NSString?
let image = UIImage(data: imageData)
return image!
}
func deCompressImage(image:UIImage) -> UIImage {
UIGraphicsBeginImageContextWithOptions(image.size, true, 0)
image.draw(at: CGPoint.zero)
let decompressedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return decompressedImage!
}
}
extension NSString {
func getNumFromString() -> String? {
var numberString: NSString?
let thisScanner = Scanner(string: self as String)
let numbers = NSCharacterSet(charactersIn: "0123456789")
thisScanner.scanUpToCharacters(from: numbers as CharacterSet, into: nil)
thisScanner.scanCharacters(from: numbers as CharacterSet, into: &numberString)
return numberString as? String;
}
}
Demo Reference