Друк необов'язкової змінної


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.

Моє запитання, чому там необов’язково (18), як я можу видалити необов’язковий та просто друк

Daniel is 18 years old.

Відповіді:


190

Ви повинні зрозуміти, що насправді є необов'язковим. Багато початківців Свіфт вважають, var age: Int?що вік - це Інт, який може мати або не мати значення. Але це означає, що вік - необов'язковий, який може або не може мати Інт.

Всередині description()функції ви не друкуєте Int, а натомість друкуєте Необов’язково. Якщо ви хочете роздрукувати Int, вам потрібно розгортати Додатково. Ви можете використовувати "необов'язкове прив'язування" для розгортання необов'язкового:

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

Якщо ви впевнені, що необов'язково містить об'єкт, ви можете використовувати "примусове розгортання":

let a = age!

Або у вашому прикладі, оскільки у вас вже є тест на нуль у функції опису, ви можете просто змінити його на:

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

Я думаю, що приклад був би трохи кращим, якби ви змінили його на використання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? означає, що Свіфт не зовсім впевнений, чи є це число Int.

Щоб видалити його, можна застосувати три методи.

1) Якщо ви абсолютно впевнені в типі, ви можете використовувати знак оклику, щоб змусити його розгортати, наприклад:

// Here is an optional variable:

var age: Int?

// Here is how you would force unwrap it:

var unwrappedAge = age!

Якщо ви примусово розгорнули необов’язковість і вона дорівнює нулю, ви можете зіткнутися з цією помилкою аварії:

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

Це не обов'язково безпечно, тому ось метод, який може запобігти збоям у випадку, якщо ви не впевнені в типі та значенні:

Методи 2 та три захищають від цієї проблеми.

2) Необов’язково розмотується необов’язково

 if let unwrappedAge = age {

 // continue in here

 }

Зауважте, що розгорнутий тип тепер Int , а не Int? .

3) Заява охоронця

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

Звідси ви можете йти вперед і використовувати розгорнуту змінну. Переконайтеся, що лише примушуйте розкручувати (за допомогою!), Якщо ви впевнені в типі змінної.

Успіхів у вашому проекті!


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 (_: роздільник: термінатор :). Однак це буде друкувати рядок у подвійних лапках.
psmythirl

@psmythirl: Добре знати! Однак іноді ви можете просто передати або вбудувати необов'язково як Stringдесь інше (наприклад, повідомлення про журнал / помилку).
Джеремі

print (d as Any)
DawnSong

7

Оновлення

Просто використовуйте me.age ?? "Unknown age!". Він працює в 3.0.2.

Стара відповідь

Без примусового розгортання (без сигналу маху / аварії, якщо нуль) ще один приємний спосіб зробити це:

(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 є умовною структурою для повернення контролю, якщо умова не виконується.

Я вважаю за краще використовувати guardнад if letблоком у багатьох ситуаціях, оскільки це дозволяє нам повернути значення, functionякщо певне значення не існує. Як і коли є функція, де змінна є інтегральною для існування, ми можемо перевірити її в операторі оператора і повернення її не існує. тобто;

guard let abc = any_variable else { return }

Якщо у нас є змінна, ми можемо використовувати 'abc' у функції поза рамкою охорони.


3

ageнеобов'язковий тип: Optional<Int>тому якщо ви порівнюєте його з нулем, він повертає помилку кожного разу, якщо він має значення або якщо ні. Щоб отримати значення, потрібно розгортати необов'язкове.

У вашому прикладі ви не знаєте, чи містить воно якесь значення, тож ви можете використовувати це замість цього:

if let myAge = age {
    // there is a value and it's currently undraped and is stored in a constant
}
else {
   // no value
}

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

2
Ви не повинні змушувати розгортати факультатив
E-Riddie


3

Якщо у вас є значення за замовчуванням:

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

або коли ім'я необов’язкове:

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


1

Я отримував необов’язковий ("Рядок") у своїх осередках перегляду таблиці.

Перша відповідь - чудова. І допоміг мені це зрозуміти. Ось що я зробив, щоб допомогти новачкам там, як я.

Оскільки я створюю масив у власному користувальницькому об’єкті, я знаю, що у нього завжди будуть елементи в першій позиції, тому я можу змусити його розгортати його в іншу змінну. Потім використовуйте цю змінну для друку або в моєму випадку встановіть текст клітинки tableview.

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

Зараз це здається простим, але мені потрібно було трохи часу, щоб розібратися.


-1

Це не точна відповідь на це питання, але одна з причин такого питання. У моєму випадку я не зміг видалити необов’язково з рядка за допомогою "якщо нехай" та "нехай охороняє".

Тому використовуйте AnyObject замість Any для швидкого видалення необов’язкового рядка.

Для відповіді зверніться за посиланням.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.