Swift设置内容抗压性

Zha*_*ang 28 ios autolayout swift

再次使用Swift,我错过了什么吗?

我有这条线:

self.itemDescription?.setContentCompressionResistancePriority(UILayoutPriorityRequired, forAxis: UILayoutConstraintAxis.Vertical);
Run Code Online (Sandbox Code Playgroud)

但是Xcode给了我一个错误:

Undefined symbols for architecture i386: "_UILayoutPriorityRequired"
Run Code Online (Sandbox Code Playgroud)

另一个斯威夫特的怪癖?

Jas*_*oss 28

解决方案:替换UILayoutPriorityRequired为1000

self.itemDescription?.setContentCompressionResistancePriority(1000, forAxis: UILayoutConstraintAxis.Vertical);
Run Code Online (Sandbox Code Playgroud)

这不是一个错误.这是对Objective-C库如何导入Swift的误解.应该理解Swift如何将代码(甚至从Apple UIKIt Libraries)导入Objective-C到Swift.

UILayoutPriority是一个浮点数.在Objective-C中,为我们预先定义了几个值.预定义的值似乎是枚举.我们可能期望在Swift中可以使用相同的枚举.

文档似乎暗示了一个枚举:

SWIFT(文档)

typealias UILayoutPriority = Float
Run Code Online (Sandbox Code Playgroud)

目标-C(文件)

enum {
   UILayoutPriorityRequired = 1000,
   UILayoutPriorityDefaultHigh = 750,
   UILayoutPriorityDefaultLow = 250,
   UILayoutPriorityFittingSizeLevel = 50,
};
typedef float UILayoutPriority;
Run Code Online (Sandbox Code Playgroud)

但是在Xcode中,如果你要求查看其中一个枚举值(例如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.
Run Code Online (Sandbox Code Playgroud)

因此,尽管我们可能会将预定义的布局优先级视为枚举值(如文档所示),但布局优先级并未真正定义为枚举; 它们被定义为常量浮点数.

对于任何知道C编程语言的人来说,存在不匹配的暗示是C枚举可能只包含int值.以下是合法的,将编译:

enum myEnum {
    JGCEnum_one = 1, // this is O.K.
    JGCEnum_two,
    JGCEnum_three
} JGCEnum;
Run Code Online (Sandbox Code Playgroud)

但是我们不能将浮点数定义为C枚举的值.以下内容无法编译:

enum myEnum {
    JGCEnum_one = 1.5, // compile error
    JGCEnum_two,
    JGCEnum_three
} JGCEnum;
Run Code Online (Sandbox Code Playgroud)

Objective-C枚举与C枚举相同(Swift枚举不同).重要的是要知道我们是否正在处理实际的整数或浮点数.因为可以使用NS_ENUM宏定义整数,然后可以将其作为Swift枚举导入Swift.

iBook说

Swift作为Swift枚举导入任何标有NS_ENUM宏的C样式枚举.这意味着枚举值名称的前缀在导入Swift时会被截断,无论它们是在系统框架中还是在自定义代码中定义的.

摘录自:Apple Inc."将Swift与Cocoa和Objective-C结合使用."iBooks

这意味着,如果UILayoutPriority 被定义为使用NS_ENUM宏观整数,它会被导入到斯威夫特斯威夫特枚举.这是UILayoutConstraintAxis的情况.

SWIFT(文档)

enum UILayoutConstraintAxis : Int {
    case Horizontal
    case Vertical
}
Run Code Online (Sandbox Code Playgroud)

目标-C(文件)

enum {
   UILayoutConstraintAxisHorizontal = 0,
   UILayoutConstraintAxisVertical = 1
};
typedef NSInteger UILayoutConstraintAxis;
Run Code Online (Sandbox Code Playgroud)

查看Objective-C头文件确认文档说的内容.

OBJECTIVE-C(头文件)

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

typedef NS_ENUM(NSInteger, UILayoutConstraintAxis) {
    UILayoutConstraintAxisHorizontal = 0,
    UILayoutConstraintAxisVertical = 1
};
Run Code Online (Sandbox Code Playgroud)

因此,至少有两种方法可以知道在Swift中是否可以使用在Objective-C中使用的预定义值:

  1. 检查文档
  2. 检查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);
Run Code Online (Sandbox Code Playgroud)

参考

  • 虽然这是一个很好的答案,描述导致问题的原因,但实际上并没有说出解决方案. (3认同)

小智 8

要记住的一件事是,即使它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 }
}
Run Code Online (Sandbox Code Playgroud)

然后你的代码可以读作:

self.itemDescription?.setContentCompressionResistancePriority(UILayoutPriority.Required, forAxis: .Vertical);
Run Code Online (Sandbox Code Playgroud)

我自己在我的一个项目中完成了这个,并认为它可能有用.