Xcode 8 / Swift 3: Biểu hiện của kiểu UIViewContoder? là cảnh báo không được sử dụng


230

Tôi đã có chức năng sau đây được biên dịch rõ ràng trước đó nhưng tạo cảnh báo bằng Xcode 8.

func exitViewController()
{
    navigationController?.popViewController(animated: true)
}

"Biểu thức của loại" UIViewControll? "Không được sử dụng".

Tại sao nó nói điều này và có một cách để loại bỏ nó?

Mã thực thi như mong đợi.

Câu trả lời:


498

TL; DR

popViewController(animated:)trả về UIViewController?và trình biên dịch sẽ đưa ra cảnh báo đó vì bạn không nắm bắt được giá trị. Giải pháp là gán nó cho dấu gạch dưới:

_ = navigationController?.popViewController(animated: true)

Thay đổi nhanh 3

Trước Swift 3, tất cả các phương thức đều có "kết quả có thể loại bỏ" theo mặc định. Không có cảnh báo sẽ xảy ra khi bạn không nắm bắt được phương thức trả về.

Để thông báo cho trình biên dịch rằng kết quả sẽ được ghi lại, bạn phải thêm @warn_unused_resulttrước khi khai báo phương thức. Nó sẽ được sử dụng cho các phương thức có dạng biến đổi (ví dụ sortsortInPlace). Bạn sẽ thêm @warn_unused_result(mutable_variant="mutableMethodHere")để nói với trình biên dịch của nó.

Tuy nhiên, với Swift 3, hành vi bị lật. Tất cả các phương thức hiện cảnh báo rằng giá trị trả về không bị bắt. Nếu bạn muốn nói với trình biên dịch rằng cảnh báo là không cần thiết, bạn thêm @discardableResulttrước khi khai báo phương thức.

Nếu bạn không muốn sử dụng giá trị trả về, bạn phải thông báo rõ ràng cho trình biên dịch bằng cách gán nó cho dấu gạch dưới:

_ = someMethodThatReturnsSomething()

Động lực để thêm điều này vào Swift 3:

  • Ngăn ngừa các lỗi có thể xảy ra (ví dụ: sử dụng sort suy nghĩ nó sẽ sửa đổi bộ sưu tập)
  • Mục đích rõ ràng là không nắm bắt hoặc cần phải nắm bắt kết quả cho các cộng tác viên khác

API UIKit dường như đứng sau về điều này, không thêm vào việc @discardableResultsử dụng hoàn toàn bình thường (nếu không phổ biến hơn) popViewController(animated:)mà không nắm bắt giá trị trả về.

Đọc thêm


15
Đây là (theo ý kiến của tôi) chắc chắn là một bước trở lại từ Swift 2, đặc biệt là khi có những phương pháp như thế này mà, mặc dù họ làm trả về một giá trị, có những trường hợp sử dụng hoàn toàn hợp lệ, nơi bạn chỉ không sử dụng nó.
Nicolas Miari

15
1. Bạn không cần let: bạn chỉ có thể gán cho _ mà không cần đặt trước lethoặc var.
còi xương

1
@rickster Không biết điều đó sẽ thêm vào câu trả lời.
tktsubota

5
2. @NicolasMiari Gửi một lỗi . Có một chú thích ( @discardableResult) cho các hàm trả về một giá trị nhưng theo đó người ta có thể bỏ qua giá trị trả về. UIKit chưa áp dụng chú thích đó cho API của họ.
gà trống

37
Đây là cú pháp khủng khiếp. Tại sao họ làm điều đó? Kinh quá.
David S.

38

Khi cuộc sống cho bạn chanh, hãy mở rộng:

import UIKit

extension UINavigationController {
    func pop(animated: Bool) {
        _ = self.popViewController(animated: animated)
    }

    func popToRoot(animated: Bool) {
        _ = self.popToRootViewController(animated: animated)
    }
}

Lưu ý rằng việc thêm một cái gì đó giống như @discardableResult func pop(animated: Bool) -> UIViewController?sẽ dẫn đến cảnh báo giống như bạn đang cố gắng tránh.

Với phần mở rộng bây giờ bạn có thể viết:

func exitViewController()
{
    navigationController?.pop(animated: true)
}

func popToTheRootOfNav() {
    navigationController?.popToRoot(animated: true)
}

Chỉnh sửa: Đã thêm popToRoot.


Đây phải là giải pháp được chấp nhận vì đây là cách khắc phục rõ ràng nhất đối với những gì chắc chắn sẽ được sửa trong bản cập nhật Xcode.
Philip Broadway

24

Trong Swift 3, bỏ qua giá trị trả về của hàm có giá trị trả về được khai báo sẽ dẫn đến cảnh báo.

Một cách để từ chối điều này là đánh dấu hàm bằng @discardableResultthuộc tính. Vì bạn không có quyền kiểm soát chức năng này, nên nó sẽ không hoạt động.

Phương pháp khác để thoát khỏi cảnh báo là gán giá trị cho _. Điều này cho trình biên dịch bạn biết phương thức trả về một giá trị nhưng bạn không muốn giữ lại nó trong bộ nhớ.

let _ = navigationController?.popViewController(animated: true)

2
Tôi đoán chúng ta sẽ phải gắn bó với sự xấu xí _cho đến khi Apple cập nhật UIKit với thuộc tính mới này.
Nicolas Miari

2
Thật không may, @discardableResultnó không hoạt động (ít nhất là nó vẫn bị vẹo với 8b4). Friedrich Schiller yêu táo thối. Có lẽ là một vấn đề về hương vị :-(
qwerty_so

5

Ảnh chụp màn hình 1

Mặc dù vậy work correctly if kept as it isnhưngnumber of warning increases.

Giải pháp đơn giản là replace it with underscore ( _ )mặc dù nó có vẻ xấu.

Eg.  _ = navigationController?.popViewController(animated: true)

Ảnh chụp màn hình 2


2

Sử dụng disardableResult trong điều kiện này.

Theo <Ngôn ngữ lập trình Swift>, Tham chiếu ngôn ngữ chương - Thuộc tính.

loại bỏResult

Áp dụng thuộc tính này cho khai báo hàm hoặc phương thức để chặn cảnh báo trình biên dịch khi hàm hoặc phương thức trả về giá trị được gọi mà không sử dụng kết quả của nó.

https://developer.apple.com/l Library / content / document / Swift / Contualual / Swift_Programming_Lingu / Attribut.html # / // numplef / doc / uid / TP40014097-CH35-ID347

Ngoài ra còn có một bản demo trong <Ngôn ngữ lập trình Swift>, Hướng dẫn ngôn ngữ chương - Phương thức.

@discardableResult
    mutating func advance(to level: Int) -> Bool {
    ...
return true
}

Bởi vì nó không nhất thiết là một lỗi đối với mã gọi phương thức Advance (to :) để bỏ qua giá trị trả về, hàm này được đánh dấu bằng thuộc tính @discardableResult. Để biết thêm thông tin về thuộc tính này, xem Thuộc tính.

https://developer.apple.com


0

Nếu bạn muốn đi theo con đường của các tiện ích mở rộng như câu trả lời của CodeReaper, bạn nên sử dụng @descardableResult. Điều này giữ tất cả các khả năng, nhưng im lặng cảnh báo.

import UIKit

extension UINavigationController {
    @discardableResult func pop(animated: Bool) -> UIViewController? {
        return self.popViewController(animated: animated)
    }

    @discardableResult func popToRoot(animated: Bool) -> [UIViewController]? {
        return self.popToRootViewController(animated: animated)
    }
}

-1

Một cách khác là bạn có thể mở khóa self.navigationController?giá trị và gọi popViewControllerhàm.

    if let navigationController = navigationController {
        navigationController.popViewController(animated: true)
    }
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.