Печать дополнительной переменной

118

Я пытаюсь использовать эти строки кода

class Student {
    var name: String
    var age: Int?

    init(name: String) {
        self.name = name
    }

    func description() -> String {
        return age != nil ? "\(name) is \(age) years old." : "\(name) hides his age."
    }
}

var me = Student(name: "Daniel")
println(me.description())
me.age = 18
println(me.description())

Приведенный выше код дает следующее

Daniel hides his age.
Daniel is Optional(18) years old.

У меня вопрос, почему там есть Optional (18), как я могу удалить необязательный и просто распечатать

Daniel is 18 years old.
Даниэль Адинугрохо
источник

Ответы:

190

Вы должны понимать, что на самом деле такое Optional. Многие новички в Swift думаютvar age: Int? что age - это Int, который может иметь или не иметь значения. Но это означает, что возраст является необязательным, который может иметь или не иметь Int.

Внутри вашей description()функции вы не печатаете Int, а вместо этого печатаете Optional. Если вы хотите распечатать Int, вам нужно развернуть Optional. Вы можете использовать «необязательную привязку», чтобы развернуть необязательный:

if let a = age {
 // a is an Int
}

Если вы уверены, что Optional содержит объект, вы можете использовать «принудительное развертывание»:

let a = age!

Или в вашем примере, поскольку у вас уже есть тест на nil в функции описания, вы можете просто изменить его на:

func description() -> String {
    return age != nil ? "\(name) is \(age!) years old." : "\(name) hides his age."
}
Apfelsaft
источник
Я думаю, что пример был бы немного лучше, если бы вы изменили его на использованиеif let age = age { return ""} else { return "" }
Куби
13
+1 за:Many Swift beginners think var age: Int? means that age is an Int which may or may not have a value. But it means that age is an Optional which may or may not hold an Int.
lee
18

Необязательный параметр означает, что Swift не совсем уверен, соответствует ли значение типу: например, Int? означает, что Swift не совсем уверен, является ли число Int.

Чтобы удалить его, вы можете использовать три метода.

1) Если вы абсолютно уверены в типе, вы можете использовать восклицательный знак, чтобы принудительно развернуть его, например:

// Here is an optional variable:

var age: Int?

// Here is how you would force unwrap it:

var unwrappedAge = age!

Если вы принудительно развернете необязательный параметр, и он равен nil, вы можете столкнуться с этой ошибкой сбоя:

введите описание изображения здесь

Это не обязательно безопасно, поэтому вот метод, который может предотвратить сбой, если вы не уверены в типе и значении:

Методы 2 и 3 защищают от этой проблемы.

2) Неявно развернутый необязательный

 if let unwrappedAge = age {

 // continue in here

 }

Обратите внимание, что развернутый тип теперь Int , а не Int? ,

3) Заявление охранника

 guard let unwrappedAge = age else { 
   // continue in here
 }

Отсюда вы можете продолжить и использовать развернутую переменную. Убедитесь, что развернули только принудительно (с помощью символа!), Если вы уверены в типе переменной.

Удачи с вашим проектом!

GJZ
источник
1
используя возраст возврата! = ноль? «(имя) (возраст!) лет». : "(имя) скрывает свой возраст".
leedream
1
Избавил меня от головной боли с проблемой, которая у меня была. Не могу вас отблагодарить.
Бруно Ресиллас
8

В целях тестирования / отладки я часто хочу выводить опциональные параметры в виде строк без необходимости всегда проверять nilзначения, поэтому я создал собственный оператор.

Я улучшил ситуацию еще больше после прочтения этого ответа в другом вопросе .

fileprivate protocol _Optional {
    func unwrappedString() -> String
}

extension Optional: _Optional {
    fileprivate func unwrappedString() -> String {
        switch self {
        case .some(let wrapped as _Optional): return wrapped.unwrappedString()
        case .some(let wrapped): return String(describing: wrapped)
        case .none: return String(describing: self)
        }
    }
}

postfix operator ~? { }
public postfix func ~? <X> (x: X?) -> String {
    return x.unwrappedString
}

Очевидно, что оператор (и его атрибуты) можно настроить по своему усмотрению или вместо этого сделать его функцией. В любом случае, это позволяет вам писать такой простой код:

var d: Double? = 12.34
print(d)     // Optional(12.34)
print(d~?)   // 12.34
d = nil
print(d~?)   // nil

Интеграция идеи протокола другого парня сделала так, что это работает даже с вложенными опциями, которые часто возникают при использовании опциональной цепочки. Например:

let i: Int??? = 5
print(i)              // Optional(Optional(Optional(5)))
print("i: \(i~?)")    // i: 5
Джереми
источник
1
Начиная с Swift 3, вы также можете использовать стандартную библиотечную функцию Swift debugPrint (_: separator: terminator :). Однако это напечатает строку в двойных кавычках.
psmythirl 08
@psmythirl: Полезно знать! Однако иногда вам может потребоваться просто передать или встроить необязательный параметр в Stringдругое место (например, журнал / сообщение об ошибке).
Джереми
print (d as Any)
DawnSong
7

Обновить

Просто используйте me.age ?? "Unknown age!". Работает в 3.0.2.

Старый ответ

Без принудительного разворачивания (нет сигнала mach / сбой, если nil) еще один хороший способ сделать это:

(result["ip"] ?? "unavailable").description,

result["ip"] ?? "unavailable" тоже должна работать, но ее нет, по крайней мере, не в 2.2

Конечно, замените «недоступный» на то, что вам подходит: «ноль», «не найдено» и т. Д.

Валентин Раду
источник
4

Чтобы развернуть необязательное использование age!вместо age. В настоящее время вы печатаете необязательное значение, которое может быть nil. Вот почему его обернули Optional.

Кирштейнс
источник
4

В быстром Optional- это то, что может быть nilв некоторых случаях. Если вы на 100% уверены, что a variableвсегда будет иметь какое-то значение и не вернет nilдобавленное! с переменной, чтобы принудительно развернуть его.

В другом случае, если вы не очень уверены в ценности, добавьте if letблок или guardубедитесь, что значение существует, иначе это может привести к сбою.

Для if letблока:

if let abc = any_variable {
 // do anything you want with 'abc' variable no need to force unwrap now.
}

Для guardзаявления:

guard условная структура для возврата управления, если условие не выполняется.

Я предпочитаю использовать guardover if letblock во многих ситуациях, поскольку он позволяет нам возвращать, functionесли определенное значение не существует. Например, когда есть функция, в которой существует интегральная переменная, мы можем проверить ее в операторе защиты, и ее возврат не существует. то есть;

guard let abc = any_variable else { return }

Если переменная существует, мы можем использовать abc в функции за пределами области защиты.

Мухаммад Явар Али
источник
3

ageявляется необязательным типом: Optional<Int>поэтому, если вы сравниваете его с nil, он каждый раз возвращает false, если он имеет значение или нет. Вам нужно развернуть необязательное, чтобы получить значение.

В вашем примере вы не знаете, содержит ли он какое-либо значение, поэтому вы можете использовать это вместо:

if let myAge = age {
    // there is a value and it's currently undraped and is stored in a constant
}
else {
   // no value
}
Greg
источник
3

Я сделал это, чтобы распечатать значение строки (свойства) из другого контроллера представления.

ViewController.swift

var testString:NSString = "I am iOS Developer"

SecondViewController.swift

var obj:ViewController? = ViewController(nibName: "ViewController", bundle: nil)
print("The Value of String is \(obj!.testString)")

Результат:

The Value of String is I am iOS Developer
iCodeAtApple
источник
2
Не следует принудительно распаковывать необязательные материалы
E-Riddie
3

Ознакомьтесь с guardзаявлением:

for student in class {
    guard let age = student.age else { 
        continue 
     }
    // do something with age
}
Фил Хадсон
источник
3

При наличии значения по умолчанию:

print("\(name) is \(age ?? 0) years old")

или если имя необязательно:

print("\(name ?? "unknown") is \(age) years old")

Арнон
источник
1

Я получал Optional («String») в своих ячейках tableview.

Первый ответ отличный. И помог мне разобраться. Вот что я сделал, чтобы помочь таким новичкам, как я.

Поскольку я создаю массив в своем настраиваемом объекте, я знаю, что в нем всегда будут элементы в первой позиции, поэтому я могу принудительно развернуть его в другую переменную. Затем используйте эту переменную для печати или, в моем случае, установите текст ячейки tableview.

let description = workout.listOfStrings.first!
cell.textLabel?.text = description

Сейчас это кажется таким простым, но мне потребовалось время, чтобы сообразить.

Джошуа танец
источник
-1

Это не точный ответ на этот вопрос, но одна из причин такого рода проблем. В моем случае мне не удалось удалить Optional из String с помощью «if let» и «guard let».

Так что используйте AnyObject вместо Any чтобы быстро удалить optional из строки.

Пожалуйста, обратитесь к ссылке для ответа.

https://stackoverflow.com/a/51356716/8334818

Прамод Подробнее
источник