-3

I've been having trouble with XCode terminating when I enter a value for Module name. It only happens half the time, so one minute it's working and value is saved to the array, the next minute the app terminates. Please help.

DetailView ControllerCode:

var courseWork: CourseWork? {
    didSet {
        dispatch_async(dispatch_get_main_queue()) {
            self.configureView()
        }

    }
}

func configureView() { // Update the user interface for the detail view

    if let detail = self.courseWork { 

        self.title = detail.valueForKey("courseWorkName")!.description 

        textFields[0].text = detail.valueForKey("moduleName") as? String //Error with this line
        textFields[1].text = detail.valueForKey("markAwarded") as? String 


func setupUIElements() {

    //text fields
    for textF in textFields {
        textF.delegate = self
    }
    textView.delegate = self

}

Code2:

func saveTHeCourseWork(fieldName: String, value: AnyObject) { 

    courseWork?.setValue(value, forKey: fieldName) 

    do {
        try courseWork?.managedObjectContext?.save() 
    } catch {
        let saveError = error as NSError 
        print(saveError) 
    }
}

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    if textField == textFields[0] { // module name field
        saveTHeCourseWork("moduleName", value: textFields[0].text!) 
    } else if textField == textFields[1] { // mark awarded
        saveTHeCourseWork("markAwarded", value: textFields[1].text!) 
    }
    return true
}

Error:

fatal error: unexpectedly found nil while unwrapping an Optional value

2 Answers2

0

Index lookup for collectionType is not safe, you have to check that the index is less than array.count first, then you can safely unwrap the value at that index. Anyway in this particular case I think this is a better way to do it:

for (index, tf) in textFields.enumerate() {
    if textField == tf {
        saveTHeCourseWork(index == 0 ? "moduleName" : "markAwarded", value: textFields[index].text!)
    }
}

The important thing is that you have to be sure the array of textfields contains a textField at the index you're searching... you're getting this error because the array have no textField at index 0.

Marco M
  • 1,185
  • 11
  • 12
  • What part of the code would I replace that with? – IOS Programmer May 15 '16 at 11:45
  • if textField == textFields[0] { // module name field saveTHeCourseWork("moduleName", value: textFields[0].text!) } else if textField == textFields[1] { // mark awarded saveTHeCourseWork("markAwarded", value: textFields[1].text!) } – Marco M May 15 '16 at 11:46
  • I just noted you have the error in another line... wait a minute... and replace that part anyway. – Marco M May 15 '16 at 11:48
  • Thanks for your help, but the same error keeps showing. Could you please let me know about the other error you mentioned? – IOS Programmer May 15 '16 at 11:51
  • No, I mean I've just seen your comment: "//Error with this line", you only need to check that textfields is not empty at the index you're searching... you got the error because the array is empty. – Marco M May 15 '16 at 11:54
  • if textFields.count >= 2 { // set values at index 0 or 1 } but anyway I suppose the array must not be empty in the line you got the error – Marco M May 15 '16 at 11:56
  • so where would I put that code? Sorry, I'm just starting out at Swift – IOS Programmer May 15 '16 at 11:57
  • Simply check why textFields is empty! It must not be empty, check that you have appended your textFieds first!, I don't see where you create the array... – Marco M May 15 '16 at 11:59
0

There is a lot of potentially unsafe unwrapping in the code for both force-unwrapping of optionals and index lookup in collection types — so could be many things. Perhaps refactoring those two methods will eliminate the issue.

Update configureView with (feel free to replace "N/A" with other fallback strings):

func configureView() {
    guard textFields.count > 1 else { return }

    self.title = self.courseWork?.valueForKey("courseWorkName")?.description ?? "N/A"
    textFields[0].text = self.courseWork?.valueForKey("moduleName") as? String ?? "N/A"
    textFields[1].text = self.courseWork?.valueForKey("markAwarded") as? String ?? "N/A"
}

And shouldChangeCharactersInRange with:

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    guard
        let index = textFields.indexOf(textField),
        let value = textField.text
    else { return true }

    switch index {
    case 0:
        saveTHeCourseWork("moduleName", value: value)
    case 1:
        saveTHeCourseWork("markAwarded", value: value)
    default:
        break
    }

    return true
}
Alex Staravoitau
  • 2,092
  • 19
  • 25