Need Assistance with sending attachments for MFMessageComposeViewController

I am coding an app where the user has the ability to send text fields and images from the app using SMS when they press "Submit Now". The following code has enabled everything to work flawlessly if there are EXACTLY three images being sent. We want to enable the user to send one photo, two photos, or even no photos (up to and including three).

Right now the app will crash if any less than three photos are included. Here is the error message:

Code Block language
"Unexpectedly found nil while unwrapping an Optional value"


Here is my section of code for the view controller responsible for sending the fields and images via SMS once the user presses "Submit Now":

Code Block language
@IBAction func SubmitNow(_ sender: Any) {
        
        print("Submission Button Has Been Pressed")
            
        if (MFMessageComposeViewController.canSendText()) && (MFMessageComposeViewController.canSendAttachments()) {
                    
                    let controller = MFMessageComposeViewController()
                    
                    controller.body = "Name: \(nameField.text!) \n\nAddress: \(addressField.text!) \n\nEmail: \(emailField.text!) \n\nTime of Day: \(notesField.text!) \n\nNotes: \(TimeOfDay.text!)"
                    
                    controller.recipients = ["our phone number"]
                    
                    controller.messageComposeDelegate = self
            
            let image1 = FreshImage1.image!
            let dataImage1 = image1.jpegData(compressionQuality: 100)
            guard dataImage1 != nil else { return }
            
            controller.addAttachmentData(dataImage1!, typeIdentifier: "image/jpeg", filename: "Image1.jpeg")
            
            self.present(controller, animated: true, completion: nil)
            
            
            let image2 = FreshImage2.image!
            let dataImage2 = image2.jpegData(compressionQuality: 100)
            guard dataImage2 != nil else { return }
            
            controller.addAttachmentData(dataImage2!, typeIdentifier: "image/jpeg", filename: "Image2.jpeg")
            
            self.present(controller, animated: true, completion: nil)
            
            
            let image3 = FreshImage3.image!
            let dataImage3 = image3.jpegData(compressionQuality: 100)
            guard dataImage3 != nil else { return }
                    
            controller.addAttachmentData(dataImage3!, typeIdentifier: "image/jpeg", filename: "Image3.jpeg")
            
            self.present(controller, animated: true, completion: nil)
                    
                
                }
        
    }



Any help that can be provided to fix this error would be appreciated. Thank you!

What are FreshImage1, FreshImage2 and FreshImage3?
How are you setting image to them?

Please show enough info.


By the way, FreshImage1, FreshImage2 and FreshImage3 are types and image is the type property of the type?
In Swift, only type names start with Capital letter.
In response to needing more information, FreshImage1, FreshImage2, and FreshImage3 refer to the types of images imported by the user. The user will have already selected these images from the prior view controller.

The app has no problem sending the correct image data to SMS, as when three photos are available, the text message attaches them correctly.

The issue is instructing the app that they can be sent even if fewer than three photos are present. Right now, if any less than three photos are available when "Submit Now" is pressed, then the app crashes.

Here is the complete code for reference:

Code Block language
import UIKit
import MessageUI
class FourthScreenViewController: UIViewController, MFMessageComposeViewControllerDelegate, UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate {
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    func pickerView( _ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        if currentTxtFldTag == 10
                  {
                      return pickOption.count
                  }
                  else
                  {
                      return ageOption.count
                  }
    }
    func pickerView( _ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        if currentTxtFldTag == 10
                  {
                      return pickOption[row]
                  }
                  else
                  {
                      return ageOption[row]
                  }
    }
    func pickerView( _ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        if currentTxtFldTag == 10
                 {
                     notesField.text = pickOption[row]
            self.view.endEditing(true)
                 }
                 else
                 {
                     TimeOfDay.text = ageOption[row]
                    self.view.endEditing(true)
                 }
    }
    
    func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
              if textField.tag == 10  // WEIGHT OPTION
              {
                  currentTxtFldTag = 10
              }
              else  // AGE OPTION
              {
                  currentTxtFldTag = 20
              }
              pickerView.reloadAllComponents()
              return true
          }
    
    let ageOption = [String](arrayLiteral: "I need a free quote on site.", "I may have more than what's shown.", "I need scheduling/pricing for ONLY what's shown.", "I have a question not offered here.")
    let pickOption = [String](arrayLiteral: "Morning", "Mid-Morning", "Mid-Day", "Afternoon")
    let pickerView = UIPickerView()
    
    var currentTxtFldTag : Int = 10
    
    func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
            
            self.dismiss(animated: true, completion: nil)
            
        }
    
    @IBOutlet weak var FreshImage1: UIImageView!
    var newImage: UIImage!
    
    @IBOutlet weak var FreshImage2: UIImageView!
    var newImage2: UIImage!
    
    
    @IBOutlet weak var FreshImage3: UIImageView!
    var newImage3: UIImage!
    
    
    
    @IBOutlet weak var nameField: UITextField!
    
    
    @IBOutlet weak var addressField: UITextField!
    
    
    @IBOutlet weak var emailField: UITextField!
    
    
    
    @IBOutlet weak var notesField: UITextField!
    
    
    
    @IBOutlet weak var TimeOfDay: UITextField!
    
    
    
    @IBAction func SubmitNow(_ sender: Any) {
        
        print("Submission Button Has Been Pressed")
            
        if (MFMessageComposeViewController.canSendText()) && (MFMessageComposeViewController.canSendAttachments()) {
                    
                    let controller = MFMessageComposeViewController()
                    
                    controller.body = "Name: \(nameField.text!) \n\nAddress: \(addressField.text!) \n\nEmail: \(emailField.text!) \n\nTime of Day: \(notesField.text!) \n\nNotes: \(TimeOfDay.text!)"
                    
                    controller.recipients = [" our phone number "]
                    
                    controller.messageComposeDelegate = self
            
            let image1 = FreshImage1.image!
            let dataImage1 = image1.jpegData(compressionQuality: 100)
            guard dataImage1 != nil else { return }
            
            controller.addAttachmentData(dataImage1!, typeIdentifier: "image/jpeg", filename: "Image1.jpeg")
            
            self.present(controller, animated: true, completion: nil)
            
            
            let image2 = FreshImage2.image!
            let dataImage2 = image2.jpegData(compressionQuality: 100)
            guard dataImage2 != nil else { return }
            
            controller.addAttachmentData(dataImage2!, typeIdentifier: "image/jpeg", filename: "Image2.jpeg")
            
            self.present(controller, animated: true, completion: nil)
            
            
            let image3 = FreshImage3.image!
            let dataImage3 = image3.jpegData(compressionQuality: 100)
            guard dataImage3 != nil else { return }
                    
            controller.addAttachmentData(dataImage3!, typeIdentifier: "image/jpeg", filename: "Image3.jpeg")
            
            self.present(controller, animated: true, completion: nil)
                    
                
                }
        
    }
    
    
    @IBAction func HomeButton(_ sender: Any) {
        
        self.performSegue(withIdentifier: "GoHome3", sender: self)
        
    }
    
    
    
    
    @IBAction func BackButton2(_ sender: Any) {
        
        self.performSegue(withIdentifier: "Back1", sender: self)
    }
    
    
    
    
    
    override func viewDidLoad() {
        
        super.viewDidLoad()
        FreshImage1.image = newImage
        FreshImage2.image = newImage2
        FreshImage3.image = newImage3
        
        pickerView.delegate = self
            pickerView.dataSource = self
            notesField.tag = 10
            TimeOfDay.tag = 20
            notesField.delegate = self
            TimeOfDay.delegate = self
            notesField.inputView = pickerView
            TimeOfDay.inputView = pickerView
        
        overrideUserInterfaceStyle = .light
    
            
        
        
        // Do any additional setup after loading the view.
    }
    @IBAction func dismissKeyboard(_ sender: Any) {
        
        self.resignFirstResponder()
    }
    
            
        
    
    
}


FreshImage1, FreshImage2, and FreshImage3 refer to the types of images

As far as I see your code, freshImage1, freshImage2 and freshImage3 are UIImageView, not images. I strongly recommend you not to use UIImageView as a storage of image.

if any less than three photos are available when "Submit Now" is pressed, then the app crashes

You are using many crash my app operators (!) , and that why your app crashes. Stop using crash my app operators.
Accepted Answer
Thanks for the code. But, please, edit it properly to avoid all these empty lines which make it impossible to read.
I did some formatting:
Code Block
import UIKit
import MessageUI
class FourthScreenViewController: UIViewController, MFMessageComposeViewControllerDelegate, UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView( _ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if currentTxtFldTag == 10
{
return pickOption.count
}
else
{
return ageOption.count
}
}
func pickerView( _ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if currentTxtFldTag == 10
{
return pickOption[row]
}
else
{
return ageOption[row]
}
}
func pickerView( _ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if currentTxtFldTag == 10
{
notesField.text = pickOption[row]
self.view.endEditing(true)
}
else
{
TimeOfDay.text = ageOption[row]
self.view.endEditing(true)
}
}
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
if textField.tag == 10 // WEIGHT OPTION
{
currentTxtFldTag = 10
}
else // AGE OPTION
{
currentTxtFldTag = 20
}
pickerView.reloadAllComponents()
return true
}
let ageOption = [String](arrayLiteral: "I need a free quote on site.", "I may have more than what's shown.", "I need scheduling/pricing for ONLY what's shown.", "I have a question not offered here.")
let pickOption = [String](arrayLiteral: "Morning", "Mid-Morning", "Mid-Day", "Afternoon")
let pickerView = UIPickerView()
var currentTxtFldTag : Int = 10
func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
self.dismiss(animated: true, completion: nil)
}
@IBOutlet weak var FreshImage1: UIImageView!
var newImage: UIImage!
@IBOutlet weak var FreshImage2: UIImageView!
var newImage2: UIImage!
@IBOutlet weak var FreshImage3: UIImageView!
var newImage3: UIImage!
@IBOutlet weak var nameField: UITextField!
@IBOutlet weak var addressField: UITextField!
@IBOutlet weak var emailField: UITextField!
@IBOutlet weak var notesField: UITextField!
@IBOutlet weak var TimeOfDay: UITextField!
@IBAction func SubmitNow(_ sender: Any) {
print("Submission Button Has Been Pressed")
if (MFMessageComposeViewController.canSendText()) && (MFMessageComposeViewController.canSendAttachments()) {
let controller = MFMessageComposeViewController()
controller.body = "Name: \(nameField.text!) \n\nAddress: \(addressField.text!) \n\nEmail: \(emailField.text!) \n\nTime of Day: \(notesField.text!) \n\nNotes: \(TimeOfDay.text!)"
controller.recipients = [" our phone number "]
controller.messageComposeDelegate = self
let image1 = FreshImage1.image!
let dataImage1 = image1.jpegData(compressionQuality: 100)
guard dataImage1 != nil else { return }
controller.addAttachmentData(dataImage1!, typeIdentifier: "image/jpeg", filename: "Image1.jpeg")
self.present(controller, animated: true, completion: nil)
let image2 = FreshImage2.image!
let dataImage2 = image2.jpegData(compressionQuality: 100)
guard dataImage2 != nil else { return }
controller.addAttachmentData(dataImage2!, typeIdentifier: "image/jpeg", filename: "Image2.jpeg")
self.present(controller, animated: true, completion: nil)
let image3 = FreshImage3.image!
let dataImage3 = image3.jpegData(compressionQuality: 100)
guard dataImage3 != nil else { return }
controller.addAttachmentData(dataImage3!, typeIdentifier: "image/jpeg", filename: "Image3.jpeg")
self.present(controller, animated: true, completion: nil)
}
}
@IBAction func HomeButton(_ sender: Any) {
self.performSegue(withIdentifier: "GoHome3", sender: self)
}
@IBAction func BackButton2(_ sender: Any) {
self.performSegue(withIdentifier: "Back1", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
FreshImage1.image = newImage
FreshImage2.image = newImage2
FreshImage3.image = newImage3
pickerView.delegate = self
pickerView.dataSource = self
notesField.tag = 10
TimeOfDay.tag = 20
notesField.delegate = self
TimeOfDay.delegate = self
notesField.inputView = pickerView
TimeOfDay.inputView = pickerView
overrideUserInterfaceStyle = .light
// Do any additional setup after loading the view.
}
@IBAction func dismissKeyboard(_ sender: Any) {
self.resignFirstResponder()
}
}

To make code more robust, replace line 98 instructions as:
Code Block
let image1 = FreshImage1.image!
let dataImage1 = image1.jpegData(compressionQuality: 100)
by

Code Block
if let image1 = FreshImage1.image { // If that succeeds, that will unwrap
let dataImage1 = image1.jpegData(compressionQuality: 100)
} else {
return
}

Do the same on lines 106 and 114.

Replace line 94
controller.body = "Name: \(nameField.text!) \n\nAddress: \(addressField.text!) \n\nEmail: \(emailField.text!) \n\nTime of Day: \(notesField.text!) \n\nNotes: \(TimeOfDay.text!)"
by
Code Block
let name = nameField.text ?? ""
let address = addressField.text ?? ""
let email = emailField.text ?? ""
let notes = notesField.text ?? ""
let time = TimeOfDay.text ?? ""
controller.body = "Name: \(name) \n\nAddress: \(address) \n\nEmail: \(email) \n\nTime of Day: \(time) \n\nNotes: \(notes)"



Claude solved it! Thank you for your help.
Need Assistance with sending attachments for MFMessageComposeViewController
 
 
Q