Cố gắng tải chế độ xem của bộ điều khiển chế độ xem trong khi nó đang phân bổ… UISearchController


80

Tôi có mã tạo một UISearchController' in my UIVIew'sviewDidLoad`.

 self.resultSearchController = ({
        let controller = UISearchController(searchResultsController: nil)
        controller.searchResultsUpdater = self
        controller.searchBar.delegate = self
        controller.dimsBackgroundDuringPresentation = false
        controller.searchBar.sizeToFit()
        controller.hidesNavigationBarDuringPresentation = false //prevent search bar from moving
        controller.searchBar.placeholder = "Search for song"

        self.myTableView.tableHeaderView = controller.searchBar

        return controller

    })()

Ngay sau khi quá trình đóng này kết thúc, cảnh báo này sẽ xuất hiện trong bảng điều khiển:

Attempting to load the view of a view controller while it is deallocating is not allowed and may result in undefined behavior (<UISearchController: 0x154d39700>)

Tôi không hiểu những gì tôi đang làm sai. Câu hỏi tương tự này không thực sự là hoàn cảnh của tôi (Ít nhất thì tôi không nghĩ vậy). Điều gì đang xảy ra?


xkcd.com/583 Hoạt động tốt nếu tôi ném nó vào Bảng VC của mình viewDidLoad(). Đề xuất a) bao gồm toàn bộ danh sách nguồn VC và b) đảm bảo rằng lỗi đang thực sự xảy ra ở đâu và khi nào bạn nghĩ là lỗi đó.
BaseZen

Ngoài ra, làm nghiên cứu hơn như: stackoverflow.com/questions/31006045/... trong đó có các lỗi tương tự
BaseZen

Vì vậy, tôi đã thực hiện một dự án nhanh chóng, mọi thứ đã làm theo phương pháp tiên đoán, không có bảng phân cảnh và tôi không có vấn đề gì, đây có phải là vấn đề của bảng phân cảnh mà bạn đang gặp phải, có lẽ, tôi không biết, nhưng tôi cho rằng bạn đang sử dụng bảng phân cảnh, phải không? Khi tôi nói lập trình, tôi có nghĩa là không có ngòi, không có kịch bản, tất cả các mã và nó hoạt động tốt
Loxx

@BaseZen Tôi đã đặt điểm ngắt trước })()và sau })(). Lỗi sẽ xuất hiện sau khi quá trình đóng kết thúc. Tôi có a UIViewController, không phải a tableViewController.
MortalMan

@Larcerax Tôi có một bảng phân cảnh. Nó chỉ chứa một điều khiển Navigation và một UIViewController (chúng được kết nối.)
MortalMan

Câu trả lời:


119

Chế độ xem của UISearchController phải được xóa khỏi chế độ xem siêu cao của nó trước khi phân bổ. (đoán nó là một lỗi)

Mục tiêu-C ...

-(void)dealloc { 
    [searchController.view removeFromSuperview]; // It works!
}

Swift 3 ...

deinit {
    self.searchController.view.removeFromSuperview()
}

Tôi đã vật lộn với vấn đề này trong một vài tuần. ^^


1
Điều này thực sự kỳ lạ ... Nhưng nó cũng đã gây ra một mẹo nhỏ cho tôi. Tôi đoán nó thực sự là một lỗi.
Mihai Fratu

22
Tôi đã gặp vấn đề tương tự với UISearchControlertôi đã phân bổ -viewDidLoad. Đó chắc chắn là một lỗi - nếu giao dịch UISearchControllerđược phân bổ trước khi chế độ xem của nó được tải, cảnh báo này sẽ xuất hiện. Nếu tôi nhấn vào trường tìm kiếm (do đó tải chế độ xem), nó sẽ không xuất hiện. Vì vậy, trong tôi dealloc, tôi gọi [self.searchController loadViewIfNeeded](mới trong iOS 9),
Leehro

4
Bình luận của @ Leehro là câu trả lời cho tôi. nó xuất hiện dưới dạngif #available(iOS 9.0, *) { self.searchController?.loadViewIfNeeded() }
Tim.

6
Tôi muốn thêm vào nhận xét của @ Leehro rằng không cần phải làm điều này trong dealloc, bạn có thể thực hiện loadViewIfNeeded trong viewDidLoad để thay thế.
Clafou

Cảm ơn @Leehro và @Clafou ... thêm lệnh gọi [self.searchController loadViewIfNeeded];(Obj-C) là câu trả lời đã giải quyết được vấn đề trong mã của tôi.
andrewbuilder

36

Đã giải quyết! Đó là một sửa chữa đơn giản. Tôi đã thay đổi mã này

class ViewController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate {

    var resultSearchController = UISearchController()

đến điều này:

 class ViewController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate {

    var resultSearchController: UISearchController!

Điều này khắc phục sự cố.


1
Tôi đã thay đổi nó theo ý bạn. :-) Dù sao đó là lý do bao gồm cả nguồn trong câu hỏi là tốt hơn, nhưng việc tìm kiếm nó trên của riêng bạn là tốt nhất ;-)
BaseZen

Tôi cũng gặp phải cảnh báo khó chịu này và, theo câu trả lời của bạn, tôi đã sửa mọi thứ. Nhưng tôi không biết tại sao! là cần thiết thay vì phân bổ một UISearchController mới ... bạn có vui lòng cho tôi không?
Nhân Mã:

Không chắc chắn, tôi cũng muốn một lời giải thích.
MortalMan

Nếu tôi thay đổi từ var resultSearchController = UISearchController () thành var resultSearchController: UISearchController! Tôi gặp lỗi nghiêm trọng: không tìm thấy bất ngờ khi mở gói một giá trị Tùy chọn trong noOfRowInSection. Tôi có một số lượng lớn mảng, đó có phải là lỗi tạo ra không? gợi ý cho tôi.
Pawriwes

Tôi đã tìm ra, thay vì thực hiện ủy quyền và nguồn dữ liệu từ bảng phân cảnh, tôi đã viết mã và vấn đề đã được giải quyết.
Pawriwes

20

Đây là phiên bản Swift phù hợp với tôi (tương tự như câu trả lời của JJHs):

deinit{
    if let superView = resultSearchController.view.superview
    {
        superView.removeFromSuperview()
    }
}

@alex Tôi đặt nó ở cuối bộ điều khiển chế độ xem khởi tạo kết quảSearchController.
nijm

2
Bạn không thực sự cần các if lettừ .removeFromSuperView()sẽ không làm bất cứ điều gì nếusuperview == nil
NSGangster

11
class SampleClass: UITableViewController, UISearchBarDelegate {

private let searchController =  UISearchController(searchResultsController: nil)

 override func viewDidLoad() {
        super.viewDidLoad()

        searchController.loadViewIfNeeded() // Add this line before accessing searchController
 }

}

10

Kết hợp một số giải pháp mà tôi quản lý để bắt đầu hoạt động bằng cách thêm các dòng vào viewDidLoad trước khi thiết lập đầy đủ UISearchController:

override func viewDidLoad() {
    super.viewDidLoad()
    self.navigationItem.rightBarButtonItem = self.editButtonItem()

    if #available(iOS 9.0, *) {
        self.resultSearchController.loadViewIfNeeded()// iOS 9
    } else {
        // Fallback on earlier versions
        let _ = self.resultSearchController.view          // iOS 8
    }
    self.resultSearchController = ({
        let controller = UISearchController(searchResultsController: nil)
        controller.searchResultsUpdater = self
        controller.dimsBackgroundDuringPresentation = false
        controller.searchBar.sizeToFit()

        self.tableView.tableHeaderView = controller.searchBar

        return controller
    })()

    self.tableView.reloadData()

}

Tôi cũng đã thử mọi giải pháp khác đưa ra ở đây, và không ai đã đàn áp các cảnh báo (mặc dù các điều khiển tìm kiếm làm việc trong thời gian chạy); điều này đã làm nó. Cảm ơn bạn!
Nicolas Miari,

Điều này cũng đã giúp tôi, nhưng tôi phải thêm dòng đó sau khi khởi chạy UISearchController. self.searchController = ({ let controller = UISearchController(searchResultsController: nil) controller.searchResultsUpdater = self controller.dimsBackgroundDuringPresentation = false controller.searchBar.delegate = self definesPresentationContext = true controller.searchBar.sizeToFit() return controller })() sau đó self.searchController.loadViewIfNeeded()
yuzer

Tại sao chúng ta cần khởi tạo trong khối?
code4latte 17/02/17

7

Trong Swift2, tôi nhận được thông báo lỗi tương tự do một lỗi rõ ràng:

let alertController = UIAlertController(title: "Oops",
    message:"bla.", preferredStyle: UIAlertControllerStyle.Alert)

alertController.addAction(UIAlertAction(title: "Ok", 
     style: UIAlertActionStyle.Default,handler: nil))

self.presentViewController(alertController, animated: true, completion: nil)

Do lỗi sao chép ngu ngốc từ chính tôi, tôi đã không thêm dòng self.presentViewController. Điều này gây ra cùng một lỗi.


7

Trong phiên bản Swift 2.2 phù hợp với tôi

deinit {
    self.searchController?.view.removeFromSuperview()
}

Tôi nghĩ nó hữu ích!


2

Nó không phải là một lỗi. Có vẻ như bạn phải tránh tạo ViewControllers mà không trình bày chúng. Vì vậy, sau khi SomeViewController()hoặc let variable: SomeViewControllerbạn phải gọi một cái gì đó như thế này self.presentViewController(yourViewController ...etc). Nếu bạn không làm điều đó, bạn sẽ nhận được cảnh báo này khi bộ điều khiển chế độ xem này sẽ được phân bổ.


2

Của tôi đang hoạt động như thế này

func initSearchControl(){

        searchController = UISearchController(searchResultsController: nil)

        if #available(iOS 9.0, *) {
            searchController.loadViewIfNeeded()
        } else {
            let _ = self.searchController.view
        }

        searchController.searchResultsUpdater = self
        searchController.dimsBackgroundDuringPresentation = false
        definesPresentationContext = true
        tableView.tableHeaderView = searchController.searchBar
        searchController.searchBar.sizeToFit()
    }

searchController.loadViewIfNeeded () giải quyết vấn đề nhưng bạn cần gọi nó sau khi khởi tạo searchController


2

Tạo bộ điều khiển tìm kiếm trong viewDidLoad()và đặt thanh tìm kiếm của nó làm chế độ xem tiêu đề của mục điều hướng không tạo ra một tham chiếu mạnh mẽ đến bộ điều khiển tìm kiếm, đó là lý do tại sao nó được phân bổ.

Vì vậy, thay vì làm điều này:

override func viewDidLoad() {
    super.viewDidLoad()
    // Create search controller
    let searchController = UISearchController(searchResultsController: nil)
    // Add search bar to navigation bar
    navigationItem.titleView = searchController.searchBar
    // Size search bar
    searchController.searchBar.sizeToFit()
}

Bạn nên làm điều này:

var searchController: UISearchController!

override func viewDidLoad() {
    super.viewDidLoad()
    // Create search controller
    searchController = UISearchController(searchResultsController: nil)
    // Add search bar to navigation bar
    navigationItem.titleView = searchController.searchBar
    // Size search bar
    searchController.searchBar.sizeToFit()
}

1

Tôi đã sử dụng câu trả lời của Derek, nhưng phải thay đổi nó một chút. Câu trả lời được cung cấp đã bị lỗi đối với tôi vì lệnh gọi loadViewIfNeeded () xảy ra trước khi kết quảSearchController được xác định. (Tuyên bố của tôi là

var resultSearchController: UISearchController!

). Vì vậy, tôi chỉ cần di chuyển nó sau đó và nó đã hoạt động.

Nếu tôi bỏ qua hoàn toàn cuộc gọi, lỗi vẫn còn, vì vậy tôi chắc chắn rằng đó là một phần thiết yếu của câu trả lời. Tôi không thể kiểm tra nó trên iOS 8.


1

Có vẻ như chế độ xem được tải chậm, nếu bạn đã cấp phát bộ điều khiển và không bao giờ hiển thị nó, chế độ xem sẽ không được tải. Trong trường hợp này, nếu bộ điều khiển được phân bổ, bạn sẽ nhận được cảnh báo này. bạn có thể hiển thị nó một lần hoặc gọi nó là phương thức loadViewIfNeed () hoặc sử dụng 'let _ = controller.view' để buộc tải chế độ xem nhằm tránh cảnh báo này.


trên iOS 8, bạn chỉ có thể sử dụng 'let _ = controller.view'.
david

0

Tôi đến bữa tiệc hơi muộn, nhưng đây là giải pháp của tôi:

var resultSearchController: UISearchController!

override func viewDidLoad()
{
    super.viewDidLoad()

    self.resultSearchController = ({
        let searchController = UISearchController(searchResultsController: nil)
        searchController.searchResultsUpdater = self
        searchController.dimsBackgroundDuringPresentation = false
        searchController.searchBar.sizeToFit()
        return searchController
    })()

    self.tableView.tableHeaderView = self.resultSearchController.searchBar
    self.tableView.reloadData()
}

Tôi hy vọng nó làm việc cho bạn.


Điều này khác với việc khởi tạo và thiết lập trực tiếp như thế nào; Ý tôi là không sử dụng cú pháp khối?
code4latte 17/02/17
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.