2016-07-03 4 views
0

두 개의 ViewController가 있습니다. 하나는 TableView와 Add Button을 가지고 있는데 두 번째 ViewController는 텍스트 필드와 액션 버튼을 가지고 있습니다. 사용자는 텍스트 필드가있는 두 번째 화면에서 tableview에 텍스트를 삽입해야합니다.한 뷰 컨트롤러에서 다른 뷰 컨트롤러로 전환하는 동안 오류가 발생했습니다.

두 개의보기 컨트롤러에 대해 별도의 신속한 파일을 만들었습니다. 두 번째보기의 경우 첫 번째보기 수업을 가져오고 있습니다. 그러나 추가 단추를 눌러 두 번째보기 컨트롤러로 이동하려고하면 선택적 랩핑 오류가 발생합니다. 다음과 같은 오류가 발생합니다. 치명적인 오류 : unexpectedly found nil while unwrapping an Optional value. 내 첫 번째보기 컨트롤러

tableview.setEditing(true, animated: true) 

코드의 tableview 있습니다 : 내 두 번째 뷰 컨트롤러에 대한

class MainScreen : UIViewController, UITableViewDataSource, UITableViewDelegate { 


var items = ["Apple", "Fish", "Dates", "Cereal", "Ice cream", "Lamb", "Potatoes", "Chicken", "Bread"] 


@IBOutlet weak var tableview: UITableView! 

override func viewDidLoad() { 
    super.viewDidLoad() 

    // Do any additional setup after loading the view, typically from a nib. 
    tableview.setEditing(true, animated: true) 

} 

override func didReceiveMemoryWarning() { 
    super.didReceiveMemoryWarning() 
    // Dispose of any resources that can be recreated. 
} 
    func numberOfSectionsInTableView(tableView: UITableView) -> Int { 
    return 1 
} 

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
    return items.count 
} 

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 

    let iD = "normal" 
    let cell = tableView.dequeueReusableCellWithIdentifier(iD, forIndexPath: indexPath) 
    cell.textLabel?.text = items[indexPath.row] 
    return cell 
} 


func tableView(tableView: UITableView, editingStyleForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCellEditingStyle { 
    return UITableViewCellEditingStyle.None 
} 



func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath) { 
    if (sourceIndexPath.row != destinationIndexPath.row){ 
     let temp = items[sourceIndexPath.row] 
     items.removeAtIndex(sourceIndexPath.row) 
     items.insert(temp, atIndex: destinationIndexPath.row) 

    } 
    tableView.reloadData() 
} 

을}

코드 그리고 디버그 모드에서, 그것은 다음 코드 줄을 강조 텍스트 필드와 내 배열 (항목)에 텍스트를 삽입하는 버튼이 있습니다.

class TextScreen : MainScreen { 


    @IBOutlet weak var keyboard: UITextField! 

    @IBAction func insert(sender: AnyObject) { 

     items.append(keyboard.text!) 

    } 


    override func viewDidLoad() { 
     super.viewDidLoad() 
     // Do any additional setup after loading the view, typically from a nib. 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
    // Dispose of any resources that can be recreated. 
    } 

}

내가 뭘 잘못하고 있는지 모르겠다. 나는 또한 스크린 샷을 첨부했다.

+0

UITableViewDataSource 및 UITableViewDelegate의 필수 기능을 구현해야합니다. – Roee84

+0

@ Roee84 My TableView가 이미 DataSource 및 Delegate에 연결되어 있습니다. 나는 스토리 보드에서 그렇게했다. 이게 무슨 뜻이야? 좀 더 설명해 주시겠습니까? 또한 셀과 모든 것을 설정했지만 코드는 여기에 표시되지 않습니다 –

+1

'tableview' 출력이'nil' 인 것처럼 보입니다. 스토리 보드에 연결 했습니까? – vacawama

답변

0

MainScreen을 서브 클래 싱하는 대신 대리인 메서드를 사용하여 처리해야하는 작업을 처리해야합니다.

프로토콜은 클래스에 대한 구조를 규정합니다. 함수가 프로토콜에 정의 된 경우. 프로토콜을 구현하는 클래스는 그 기능을 가져야한다. Delegate = self와 같이 MainScreen에서 대리자를 참조하면 대리자를 보유한 클래스가 프로토콜에 지정된 모든 함수를 실행할 수 있습니다. 이렇게하면 TextScreen의 함수에있는 데이터가 MainScreen에 구현 된 함수로 전달됩니다.

문자열을 배열에 추가하려면 문자열을 보내거나 처리하는 함수가 필요합니다. 보낸 사람을 포함시키는 것은 에티켓입니다.

이 대리자를 사용하고자하는 클래스 사이의 링크를 생성합니다 :

protocol TextScreenDelegate { 
    func sendTextToDelegate(sender: TextScreen, text: String) 
} 

지금 당신이 그 클래스의 프로퍼티로 TextScreen보기에 대리인을 배치해야합니다 :

프로토콜을 만들기 데이터 및 데이터를 보유하는 클래스. TextScreen의 프로토콜의 메소드가 실행 될 때, 예를 들어, 그것을 참조 된 뷰쪽으로 갈 것입니다 (() delegate.sendTextToDelegate는) prepareforSegue의 MainScreen 지금 MainScreen가 준수 할

var delegate : TextScreenDelegate? 

을 (나중에 참조) 새로 만든 프로토콜을 다음과 같이 추가하십시오.

이제 MainScreen이이 프로토콜을 준수하는지 확인해야합니다. UITableView 등을 사용하는 경우 자신의 프로토콜을 추가해야합니다. 프로토콜 구현을 사용하지 않는다면 TableView가 작동하지 않는다는 것을 기억하십시오. TextScreen도 마찬가지입니다!

class MainScreen : UIViewController, UITableViewDataSource, UITableViewDelegate, TextScreenDelegate 

위에 작성된 위임 방법이 누락되어 준수하지 않는다고합니다. 이것을 구현하고 당신이 원하는 것을하십시오 :

이제 MainScreen에 프로토콜을 추가 했으므로 프로토콜에서 직접 정의한 기능을 만들어야합니다. 거기에있는 모든 기능은 다음과 같이 당신의 MainScreen에 추가해야합니다 :

func sendTextToDelegate(sender : TextScreen, text : String) { 
    self.items.append(text) 
} 

는 텍스트 뷰 당신이 당신이 그것을 참조 할 필요가 대리인에게 데이터를 전파 할 것을 알려 할 수 있으려면. prepareForSegue은 다음과 같이 보입니다.

위의 TextScreen과 MainScreen 사이의 링크를 만들었습니다. (프로토콜 TextScreenDelegate을 구현)을 MainScreen이 남아

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 
    if segue.identifier == "YourIdentifier" { 
     if let vc = segue.destinationViewController as? TextScreen { 
      vc.delegate = self 
     } 
    } 
} 

알 이제 TextScreen에있는 함수를 호출하는 것입니다 (vc.delegate = 자기 참조) 링크에 사용됩니다! 당신이 당신의 행동을 실행할 때 대의원에게 알리십시오! 이제 TextScreen에서 대리자 메서드를 호출 할 수 있습니다.

@IBAction func insert(sender: AnyObject) { 

    // Always check if exists! 
    guard let text = self.keyboard.text 
     else { 
      print("error - no text in keyboard") 
      return 
    } 
    delegate?.sendTextToDelegate(sender: self, text: text) 
} 

가 TextScreen가있는 UIView 다시하지 MainScreen의 서브 클래스 있는지 확인 : 코드를 사용

TextScreen : UIView 

그것은 그 자체에보기이다)

이는 것 같다 당신이하고 싶은 일을 처리하는 데 훨씬 깨끗한 접근법이 될 수 있습니다.

- 편집 2 -

는 대리자 메서드를 테스트하는 더러운 방법이있다. AppDelegate에 배열을 만들고 추가하십시오. 당신의 MainScreen.swift에서 지금

var items : [String] = ["Apple", "Fish", "Dates", "Cereal", "Ice cream", "Lamb", "Potatoes", "Chicken", "Bread"] 

AppDelegate.swift

에서

변화에 대한 항목 : 당신의 viewDidLoad

var items : [String] = [] 

과의()

let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate 
self.items = appDelegate.items 
self.tableView.reloadData() 

을 그리고 y ou TextScreen.swift

let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate 
appDelegate.items.append('your item') 

이렇게하면 AppDelegate에 배열로 저장됩니다. 그러나 이것은 tableView의 테스트 목적으로 만 권장됩니다. 올바른 방법은 핵심 데이터를 사용하는 것입니다. 어느 구글에 예제가 많이 있습니다.

+0

많이 고마워요! 그러나 바보처럼 들릴지 모르지만 프로토콜을 읽지 않아 내가 작성한 대부분의 코드를 이해하지 못합니다. 날 데려 갈 수 있니? 또한, 내가 제대로 이해한다면, 나는 MainScreen 파일에 프로토콜을 만들 수 있습니까? 도와주세요. 또한 TextScreen은 MainScreen에서 가져와야합니다. 맞습니까? UIViewController 아닌가요? –

+0

나는 코드에서 prepareForSegue의 작동과 이유를 이해하지 못합니다. 설명해 주시겠습니까? –

+0

내 대답을 업데이트했습니다. 다시 확인해 주시겠습니까? 이해하지 못하면 알려주세요! 1 주일 후에 삼킬 약이 될 수 있습니다.) – Emptyless

관련 문제