質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.32%

  • Swift

    5084questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

swift topViewController

受付中

回答 1

投稿 2017/07/17 15:15

  • 評価
  • クリップ 0
  • VIEW 90

3n10

score 0

前提・実現したいこと

swift初心者です。
データ管理をするアプリケーションを、参考書通りに作成しています。
エラーの原因、対処法を教えていただきたいです。

発生している問題・エラーメッセージ

viewDidLoad() の最後の文に出ました。

value of type 'UIViewController' has no member 'topViewController'

該当のソースコード

import UIKit
import CoreData

class MasterViewController: UITableViewController, NSFetchedResultsControllerDelegate {

    var detailViewController: DetailViewController? = nil
    var managedObjectContext: NSManagedObjectContext? = nil

    override func awakeFromNib() {
        super.awakeFromNib()
        if UIDevice.currentDevice().userInterfaceIdiom == .Pad {
            self.clearsSelectionOnViewWillAppear = false
            self.preferredContentSize = CGSize(width: 320.0, height: 600.0)
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationItem.leftBarButtonItem = self.editButtonItem()
        // ボタンが押された時に呼び出されるメソッドをshowAlert:に変更する
        let addButton = UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: "showAlert")
        self.navigationItem.rightBarButtonItem = addButton
        if let split = self.splitViewController {
            let controllers = split.viewControllers
            __###self.detailViewController = controllers[controllers.count-1].topViewController as? DetailViewController__
        }
    }

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

    func showAlert() {
        let alertController = UIAlertController(title: "新規作成",
            message: "名前を入力してください",
            preferredStyle: .Alert)
        // アラートビューにテキストフィールドを追加
        alertController.addTextFieldWithConfigurationHandler(nil)
        // やめるボタン
        let cancelAction = UIAlertAction(title: "やめる", style: .Cancel, handler: nil)
        // 作成するボタン
        let otherAction = UIAlertAction(title: "作成する", style: .Default) {
            [unowned self] action in
            if let textFields = alertController.textFields {
                let textField = textFields[0] 
                self.insertNewObject(textField.text!)
            }
        }
        alertController.addAction(cancelAction)
        alertController.addAction(otherAction)
        // アラートビューの表示
        self.presentViewController(alertController, animated: true, completion: nil)
    }

    func insertNewObject(name: String) {
        let context = self.fetchedResultsController.managedObjectContext
        let entity = self.fetchedResultsController.fetchRequest.entity!
        // castオブジェクトを生成する
        let cast = NSEntityDescription.insertNewObjectForEntityForName(entity.name!, inManagedObjectContext: context)
        // worktimeオブジェクトを生成する
        let worktime = NSEntityDescription.insertNewObjectForEntityForName("WorkTime", inManagedObjectContext: context)
        // personオブジェクトに名前とAddressオブジェクトをセットする
        cast.setValue(name, forKey: "name")
        cast.setValue(worktime, forKey: "worktime")
        // データの保存
        do {
            try context.save()
        } catch {
            // Replace this implementation with code to handle the error appropriately.
            // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            //print("Unresolved error \(error), \(error.userInfo)")
            abort()
        }

    }

    // MARK: - Segues
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        print("遷移元ビューコントローラー\(segue.sourceViewController)")
        print("遷移先ビューコントローラー\(segue.destinationViewController)")
        if segue.identifier == "showDetail" {
            if let indexPath = self.tableView.indexPathForSelectedRow {
                let object = self.fetchedResultsController.objectAtIndexPath(indexPath) as! Cast
                let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController
                controller.detailItem = object
                controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
                controller.navigationItem.leftItemsSupplementBackButton = true
            }
        }
    }

    // MARK: - Table View
    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return self.fetchedResultsController.sections!.count
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        let sectionInfo = self.fetchedResultsController.sections![section] 
        return sectionInfo.numberOfObjects
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) 
        self.configureCell(cell, atIndexPath: indexPath)
        return cell
    }

    override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        // Return false if you do not want the specified item to be editable.
        return true
    }

    override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
        if editingStyle == .Delete {
            let context = self.fetchedResultsController.managedObjectContext
            context.deleteObject(self.fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject)

            do {
                try context.save()
            } catch {
                // Replace this implementation with code to handle the error appropriately.
                // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                //print("Unresolved error \(error), \(error.userInfo)")
                abort()
            }
        }
    }

    func configureCell(cell: UITableViewCell, atIndexPath indexPath: NSIndexPath) {
        let object = self.fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject
        cell.textLabel!.text = object.valueForKey("name")!.description
    }

    // MARK: - Fetched results controller
    var fetchedResultsController: NSFetchedResultsController {
        // 既にオブジェクトが存在していればオブジェクトを返却して処理終了
        if _fetchedResultsController != nil {
            return _fetchedResultsController!
        }
        /*
        * 以下このプロパティに初めてアクセスされた時の記述
        */
        // フェッチリクエストオブジェクトの生成
        let fetchRequest = NSFetchRequest()

        // エンティティ記述を取得
        let entity = NSEntityDescription.entityForName("Cast",
            inManagedObjectContext: self.managedObjectContext!)
        fetchRequest.entity = entity

        // 一度に取得するデータのサイズを指定
        fetchRequest.fetchBatchSize = 20

        // データの並び順を設定
        let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
        _ = [sortDescriptor]
        fetchRequest.sortDescriptors = [sortDescriptor]

        // Edit the section name key path and cache name if appropriate.
        // nil for section name key path means "no sections".
        let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext!, sectionNameKeyPath: nil, cacheName: "Master")
        aFetchedResultsController.delegate = self
        _fetchedResultsController = aFetchedResultsController

        // データの読み込みを実行
        do {
            try self.fetchedResultsController.performFetch()
        } catch {
            fatalError("Failed to initalize FetchResultsController: \(error)")
        }

        return _fetchedResultsController!
    }
    var _fetchedResultsController: NSFetchedResultsController? = nil

    func controllerWillChangeContent(controller: NSFetchedResultsController) {
        self.tableView.beginUpdates()
    }

    func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
        switch type {
        case .Insert:
            self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
        case .Delete:
            self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
        default:
            return
        }
    }

...

試したこと

課題に対してアプローチしたことを記載してください

補足情報(言語/FW/ツール等のバージョンなど)

swift xcode

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

0

エラーは UIViewController は topViewController をメンバーに持っていない、という意味になります。

topViewController は UINavigationController のメンバーです。
topViewController - UINavigationController 

下記コードの controllers[controllers.count - 1] の箇所で NavigationController が返ってくることを期待した記述となっていますが、実際には UIViewController が返ってきているため、エラーが発生しているものと推測します。

self.detailViewController = controllers[controllers.count-1].topViewController as? DetailViewController

topViewController を参照する前に UINavigationController かどうか型のチェックを丁寧に行えば、エラーを解消できると思います。

投稿 2017/07/17 21:13

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

ただいまの回答率

91.32%

関連した質問

同じタグがついた質問を見る

  • Swift

    5084questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています