Подтвердить что ты не робот

Скоростное сопротивление сжатию содержимого

С помощью Swift снова я что-то пропустил?

У меня есть эта строка:

self.itemDescription?.setContentCompressionResistancePriority(UILayoutPriorityRequired, forAxis: UILayoutConstraintAxis.Vertical);

Но Xcode дает мне ошибку:

Undefined symbols for architecture i386: "_UILayoutPriorityRequired"

Еще одна из причуд Swift?

4b9b3361

Ответ 1

Решение: замените UILayoutPriorityRequired на 1000

self.itemDescription?.setContentCompressionResistancePriority(1000, forAxis: UILayoutConstraintAxis.Vertical);

Это не ошибка. Это неправильное понимание того, как библиотеки Objective-C импортируются в Swift. Следует понимать, как Swift импортирует код (даже из библиотек Apple UIKIt) из Objective-C в Swift.

UILayoutPriority - это float. В Objective-C для нас предопределена пара значений. Предварительно определенные значения выглядят как перечисление. Мы могли бы ожидать, что те же перечисления будут доступны нам в Swift.

Документация, похоже, подразумевает перечисление:

SWIFT (документация)

typealias UILayoutPriority = Float

OBJECTIVE-C (Документация)

enum {
   UILayoutPriorityRequired = 1000,
   UILayoutPriorityDefaultHigh = 750,
   UILayoutPriorityDefaultLow = 250,
   UILayoutPriorityFittingSizeLevel = 50,
};
typedef float UILayoutPriority;

Но в Xcode, если вы попросите увидеть определение одного из этих значений enum (например, UILayoutPriorityRequired), вы увидите, что они фактически определены в файле заголовка как постоянные поплавки.

OBJECTIVE-C (файл заголовка)

typedef float UILayoutPriority;
static const UILayoutPriority UILayoutPriorityRequired NS_AVAILABLE_IOS(6_0) = 1000; // A required constraint.  Do not exceed this.
static const UILayoutPriority UILayoutPriorityDefaultHigh NS_AVAILABLE_IOS(6_0) = 750; // This is the priority level with which a button resists compressing its content.
static const UILayoutPriority UILayoutPriorityDefaultLow NS_AVAILABLE_IOS(6_0) = 250; // This is the priority level at which a button hugs its contents horizontally.

Итак, хотя нам может показаться, что заранее определенные приоритеты макета являются значениями перечисления (как предполагает документация), приоритеты компоновки на самом деле не определены как перечисления; они определяются как постоянные поплавки.

Подсказка о том, что существует неправильное совпадение - для тех, кто знает язык программирования C, - это то, что C-перечисление может содержать только значения int. Следующее правовое и будет компилироваться:

enum myEnum {
    JGCEnum_one = 1, // this is O.K.
    JGCEnum_two,
    JGCEnum_three
} JGCEnum;

Но мы не можем определить float как значения для C перечислений. Следующие команды не будут компилироваться:

enum myEnum {
    JGCEnum_one = 1.5, // compile error
    JGCEnum_two,
    JGCEnum_three
} JGCEnum;

OBJECTIVE-C перечисления такие же, как C перечисления (Swift перечислены разные). Важно знать, имеем ли мы дело с действительными целыми числами или поплавками. Поскольку целые числа могут быть определены с помощью макроса NS_ENUM, который затем может быть импортирован в Swift как переименование Swift.

В iBook говорится:

Swift импортирует как перечисление Swift любое перечисление C-стиля, отмеченное макросом NS_ENUM. Это означает, что префиксы для имен значений перечисления усекаются, когда они импортируются в Swift, независимо от того, определены ли они в системных рамках или в пользовательском коде.

Отрывок из: Apple Inc. "Использование Swift с Cocoa и Objective-C." iBooks

Это означает, что если UILayoutPriority был определен как целое число с использованием макроса NS_ENUM, он был бы импортирован в Swift как переименование Swift. Это относится к UILayoutConstraintAxis.

SWIFT (документация)

enum UILayoutConstraintAxis : Int {
    case Horizontal
    case Vertical
}

OBJECTIVE-C (Документация)

enum {
   UILayoutConstraintAxisHorizontal = 0,
   UILayoutConstraintAxisVertical = 1
};
typedef NSInteger UILayoutConstraintAxis;

Глядя на заголовочный файл Objective-C, подтверждает, что говорится в документации.

OBJECTIVE-C (файл заголовка)

//
// UIView Constraint-based Layout Support
//

typedef NS_ENUM(NSInteger, UILayoutConstraintAxis) {
    UILayoutConstraintAxisHorizontal = 0,
    UILayoutConstraintAxisVertical = 1
};

Итак, существует как минимум два способа узнать, доступно ли предварительно определенное значение, которое вы используете для использования в Objective-C в Swift:

  • проверить документацию
  • проверьте файл заголовка в Objective-C (найденный, щелкнув правой кнопкой мыши значение, а затем выбрав "Перейти к определению" )

Есть еще один способ узнать, используется ли typedef для использования константа или перечисление. В коде проверьте, существует ли адрес константы. Константы имеют адрес памяти, а перечисления - нет. См. Код ниже.

// this line will compile and run just fine. 
// UILayoutPriorityDefaultHigh is a constant and has a memory address
// the value will be true if the device is running iOS 6.0 or later
// and false otherwise
BOOL predefinedValueIsAvailable = (NULL != &UILayoutPriorityDefaultHigh);

// this line will not compile
// UILayoutConstraintAxisHorizontal is an enum (NOT a constant) 
// and does not have a memory address
predefinedValueIsAvailable = (NULL != &UILayoutConstraintAxisHorizontal);

Ссылки

Ответ 2

Следует иметь в виду, что даже если UILayoutPriority является псевдонимом Float, вы используете Swift, и вы можете использовать расширение для создания семантических констант для этих значений:

extension UILayoutPriority {
    static var Low: Float { return 250.0 }
    static var High: Float { return 750.0 }
    static var Required: Float { return 1000.0 }
}

Затем вы можете читать код:

self.itemDescription?.setContentCompressionResistancePriority(UILayoutPriority.Required, forAxis: .Vertical);

Я сделал это сам в одном из своих проектов и подумал, что это может быть полезно.