Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift set content compression resistance

Using Swift again, am I missing something?

I have this line:

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

But Xcode is giving me an error:

Undefined symbols for architecture i386: "_UILayoutPriorityRequired" 

Another one of Swift's quirks?

like image 684
Zhang Avatar asked Nov 30 '14 06:11

Zhang


People also ask

What is content compression resistance?

And the Content Compression Resistance is, how much a view "resists" getting smaller The View with higher resistance priority value is the one that will resist compression.

What is content hugging priority and content compression resistance priority?

The content-hugging priority represents the resistance a view has to grow larger than its intrinsic content size. Conversely, the compression-resistance priority represents the resistance a view has to shrink beyond its intrinsic content size.

How do you set up content hugging?

The Content Hugging Priority resolves this confusion. Setting any one of the labels Content Hugging Priority to greater than the other does the trick, and the one with higher priority hugs its content more and make the other expand more than its intinsic content. we get to see this, Makes sense right?

What is priority in Autolayout IOS?

The priority really come in to play only if two different constraints conflict. The system will give importance to the one with higher priority. So, Priority is the tie-breaker in the autolayout world.


1 Answers

Solution: replace UILayoutPriorityRequired with 1000

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

This is not a bug. It is a misunderstanding of how Objective-C libraries are imported into Swift. It should be understood how Swift imports code (even from the Apple UIKIt Libraries) from Objective-C into Swift.

UILayoutPriority is a float. In Objective-C, a couple of values have been pre-defined for us. The pre-defined values appear to be an enum. We might expect that the same enums would be available to us in Swift.

The documentation does seem to imply an enum:

SWIFT (Documentation)

typealias UILayoutPriority = Float 

OBJECTIVE-C (Documentation)

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

But in Xcode, if you ask to see the defintion of one of these enum values (UILayoutPriorityRequired, for example), you will see that they are actually defined in the header file as constant floats.

OBJECTIVE-C (Header file)

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. 

So although we may like to think of the pre-defined layout priorities as enum values (as the documentation suggests) the layout priorities are not really defined as enums; they are defined as constant floats.

A hint that there is a mis-match -- for anyone that knows the C programming language -- is that a C enum may only contain int values. The following is legal and will compile:

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

But we can not define floats as values for C enums. The following will not compile:

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

Objective-C enums are the same as C enums (Swift enums are different). It is important to know if we are dealing with actual integers or floats. Because integers can be defined using the NS_ENUM macro, which can then be imported to Swift as a Swift enum.

The iBook says

Swift imports as a Swift enumeration any C-style enumeration marked with the NS_ENUM macro. This means that the prefixes to enumeration value names are truncated when they are imported into Swift, whether they’re defined in system frameworks or in custom code.

Excerpt From: Apple Inc. “Using Swift with Cocoa and Objective-C.” iBooks

That means that if UILayoutPriority had been defined as an integer using the NS_ENUM macro, it would have been imported into Swift as Swift enum. This is the case for UILayoutConstraintAxis.

SWIFT (Documentation)

enum UILayoutConstraintAxis : Int {     case Horizontal     case Vertical } 

OBJECTIVE-C (Documentation)

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

Looking at the Objective-C header file confirms what the documentation says.

OBJECTIVE-C (Header File)

// // UIView Constraint-based Layout Support //  typedef NS_ENUM(NSInteger, UILayoutConstraintAxis) {     UILayoutConstraintAxisHorizontal = 0,     UILayoutConstraintAxisVertical = 1 }; 

So there are at least two ways to know if a pre-defined value you are used to using in Objective-C is available in Swift:

  1. check the documentation
  2. check the header file in Objective-C (found by right-clicking the value and then selecting "Jump to Definition")

There is one more way to see if a typedef you are used to using is a constant or an enum. In code, test to see if the address of the constant exists. Constants have a memory address, while enums do not. See the code below.

// 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); 

References

  • Using Layout Priority in Swift
  • Xcode Documentation (iOS 8.2)
  • Apple Inc. “Using Swift with Cocoa and Objective-C.” iBooks
like image 198
Jason Cross Avatar answered Sep 28 '22 11:09

Jason Cross