Strange exception in layouts

强颜欢笑 提交于 2019-12-20 10:34:38

问题


Try call this method:

avatarIconImageView.setContentHuggingPriority(UILayoutPriorityDefaultLow, forAxis: UILayoutConstraintAxis.Horizontal)

and catch this exception:

Undefined symbols for architecture armv7:
"_UILayoutPriorityDefaultLow", referenced from: __TFC13TCProject_iOS36TCAvatarWithCounterUniversalCellView22configureBodyCellViewsfS0_FT_T_ in TCAvatarUniversalCellView.o ld: symbol(s) not found for architecture armv7 clang: error: linker command failed with exit code 1 (use -v to see invocation)

what it means?


回答1:


This looks like a bug in the iOS 8 SDK. You can work around this by just passing in a raw value.

  • UILayoutPriorityDefaultRequired = 1000
  • UILayoutPriorityDefaultHigh = 750
  • UILayoutPriorityDefaultLow = 250

In your case

avatarIconImageView.setContentHuggingPriority(250, forAxis: UILayoutConstraintAxis.Horizontal)



回答2:


This is not a bug. It is a shortcoming of an expectation for the import of Objective-C libraries 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 suggests an enum:

Declaration SWIFT

typealias UILayoutPriority = Float

OBJECTIVE-C

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.

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 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,
    JGCEnum_two,
    JGCEnum_three
} JGCEnum;

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

    enum myEnum {
        JGCEnum_one = 1.5, // compilation 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. https://itun.es/us/1u3-0.l

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.

Declaration SWIFT

enum UILayoutConstraintAxis : Int {
    case Horizontal
    case Vertical
}

OBJECTIVE-C

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

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

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

  • https://www.blogger.com/blogger.g?blogID=1591443959382526146#editor/target=post;postID=5044844235580349879;onPublishedMenu=allposts;onClosedMenu=allposts;postNum=0;src=postname
  • Xcode Documentation (iOS 8.2)
  • Apple Inc. “Using Swift with Cocoa and Objective-C.” iBooks. https://itun.es/us/1u3-0.l


来源:https://stackoverflow.com/questions/25881872/strange-exception-in-layouts

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!