MST

星途 面试题库

面试题:Objective-C 自动布局在跨平台(iOS 与 macOS)开发中的差异与处理

在使用Objective-C同时开发iOS和macOS应用时,虽然都使用自动布局技术,但两者存在一些差异。请详细说明这些差异,比如约束语法、布局优先级处理、视图特性等方面。并举例说明如何针对这些差异进行代码编写,以确保应用在两个平台上都能正确布局。
26.3万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

约束语法差异

  • iOS:在iOS中,常用的约束语法方式有以下几种:
    • 使用NSLayoutConstraint类的constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:方法,例如:
UIView *view1 = [[UIView alloc] init];
UIView *view2 = [[UIView alloc] init];
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:view1
                                                              attribute:NSLayoutAttributeLeading
                                                              relatedBy:NSLayoutRelationEqual
                                                                 toItem:view2
                                                              attribute:NSLayoutAttributeLeading
                                                             multiplier:1.0
                                                               constant:10];
  • 使用VFL(Visual Format Language),例如:
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[view1]-10-[view2]-10-|"
                                                                options:0
                                                                metrics:nil
                                                                  views:@{@"view1": view1, @"view2": view2}];
  • 使用NSLayoutConstraintactivateConstraints:方法批量添加约束,例如:
[NSLayoutConstraint activateConstraints:@[constraint1, constraint2, constraint3]];
  • macOS:在macOS中,约束语法与iOS类似,但视图类为NSView。也可以使用NSLayoutConstraint类的方法,例如:
NSView *view1 = [[NSView alloc] init];
NSView *view2 = [[NSView alloc] init];
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:view1
                                                              attribute:NSLayoutAttributeLeading
                                                              relatedBy:NSLayoutRelationEqual
                                                                 toItem:view2
                                                              attribute:NSLayoutAttributeLeading
                                                             multiplier:1.0
                                                               constant:10];

不同之处在于,macOS中可以使用NSStackView来更方便地进行布局管理,它可以自动创建和管理子视图之间的约束。例如:

NSStackView *stackView = [[NSStackView alloc] initWithViews:@[view1, view2]];
stackView.orientation = NSUserInterfaceLayoutOrientationHorizontal;

布局优先级处理差异

  • iOS:iOS中每个约束都有一个优先级(UILayoutPriority),默认优先级为UILayoutPriorityRequired(1000)。当布局出现冲突时,优先级低的约束会被打破。例如,一个视图同时有水平方向的宽度约束和压缩阻力优先级不同的情况:
UIView *view = [[UIView alloc] init];
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:view
                                                                  attribute:NSLayoutAttributeWidth
                                                                  relatedBy:NSLayoutRelationEqual
                                                                     toItem:nil
                                                                  attribute:NSLayoutAttributeNotAnAttribute
                                                                 multiplier:1.0
                                                                   constant:200];
widthConstraint.priority = UILayoutPriorityDefaultLow;
  • macOS:macOS中同样有优先级概念,使用NSLayoutConstraintpriority属性。但在实际应用中,macOS布局优先级的使用场景和iOS略有不同,例如在处理窗口大小变化时,对于一些固定大小视图和可拉伸视图的布局优先级设置。比如一个固定宽度的按钮和一个可拉伸的文本视图:
NSButton *button = [[NSButton alloc] init];
NSTextView *textView = [[NSTextView alloc] init];
NSLayoutConstraint *buttonWidthConstraint = [NSLayoutConstraint constraintWithItem:button
                                                                        attribute:NSLayoutAttributeWidth
                                                                        relatedBy:NSLayoutRelationEqual
                                                                           toItem:nil
                                                                        attribute:NSLayoutAttributeNotAnAttribute
                                                                       multiplier:1.0
                                                                         constant:100];
buttonWidthConstraint.priority = NSLayoutPriorityDefaultHigh;

视图特性差异

  • iOS:iOS视图有一些特定的特性,如contentMode用于控制视图内容的显示方式(如UIViewContentModeScaleAspectFill等),clipsToBounds用于控制是否裁剪超出视图边界的内容。例如:
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"example"]];
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.clipsToBounds = YES;
  • macOS:macOS视图同样有类似功能,但命名和一些细节不同。例如NSViewwantsLayer属性用于启用图层支持,进而可以设置类似裁剪等效果。NSImageViewimageScaling属性控制图片缩放方式,例如:
NSImageView *imageView = [[NSImageView alloc] init];
imageView.image = [NSImage imageNamed:@"example"];
imageView.imageScaling = NSImageScaleProportionallyUpOrDown;
imageView.wantsLayer = YES;
imageView.layer.masksToBounds = YES;

针对差异的代码编写示例

// 假设在一个跨平台项目中有一个视图,在iOS和macOS上都要实现相同的布局
// 1. 导入相关头文件
#ifdef TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#else
#import <AppKit/AppKit.h>
#endif

// 定义视图相关属性
#ifdef TARGET_OS_IPHONE
@interface MyViewController : UIViewController
@property (nonatomic, strong) UIView *mainView;
@end
#else
@interface MyViewController : NSViewController
@property (nonatomic, strong) NSView *mainView;
@end
#endif

@implementation MyViewController

- (void)viewDidLoad {
    [super viewDidLoad];
#ifdef TARGET_OS_IPHONE
    self.mainView = [[UIView alloc] init];
    self.mainView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:self.mainView];
    NSLayoutConstraint *leadingConstraint = [NSLayoutConstraint constraintWithItem:self.mainView
                                                                        attribute:NSLayoutAttributeLeading
                                                                        relatedBy:NSLayoutRelationEqual
                                                                           toItem:self.view
                                                                        attribute:NSLayoutAttributeLeading
                                                                       multiplier:1.0
                                                                         constant:20];
    NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self.mainView
                                                                     attribute:NSLayoutAttributeTop
                                                                     relatedBy:NSLayoutRelationEqual
                                                                        toItem:self.view
                                                                     attribute:NSLayoutAttributeTop
                                                                    multiplier:1.0
                                                                      constant:20];
    NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:self.mainView
                                                                       attribute:NSLayoutAttributeWidth
                                                                       relatedBy:NSLayoutRelationEqual
                                                                          toItem:nil
                                                                       attribute:NSLayoutAttributeNotAnAttribute
                                                                      multiplier:1.0
                                                                        constant:200];
    NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:self.mainView
                                                                        attribute:NSLayoutAttributeHeight
                                                                        relatedBy:NSLayoutRelationEqual
                                                                           toItem:nil
                                                                        attribute:NSLayoutAttributeNotAnAttribute
                                                                       multiplier:1.0
                                                                         constant:100];
    widthConstraint.priority = UILayoutPriorityDefaultLow;
    [NSLayoutConstraint activateConstraints:@[leadingConstraint, topConstraint, widthConstraint, heightConstraint]];
    self.mainView.backgroundColor = [UIColor redColor];
#else
    self.mainView = [[NSView alloc] init];
    self.mainView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:self.mainView];
    NSLayoutConstraint *leadingConstraint = [NSLayoutConstraint constraintWithItem:self.mainView
                                                                        attribute:NSLayoutAttributeLeading
                                                                        relatedBy:NSLayoutRelationEqual
                                                                           toItem:self.view
                                                                        attribute:NSLayoutAttributeLeading
                                                                       multiplier:1.0
                                                                         constant:20];
    NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self.mainView
                                                                     attribute:NSLayoutAttributeTop
                                                                     relatedBy:NSLayoutRelationEqual
                                                                        toItem:self.view
                                                                     attribute:NSLayoutAttributeTop
                                                                    multiplier:1.0
                                                                      constant:20];
    NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:self.mainView
                                                                       attribute:NSLayoutAttributeWidth
                                                                       relatedBy:NSLayoutRelationEqual
                                                                          toItem:nil
                                                                       attribute:NSLayoutAttributeNotAnAttribute
                                                                      multiplier:1.0
                                                                        constant:200];
    NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:self.mainView
                                                                        attribute:NSLayoutAttributeHeight
                                                                        relatedBy:NSLayoutRelationEqual
                                                                           toItem:nil
                                                                        attribute:NSLayoutAttributeNotAnAttribute
                                                                       multiplier:1.0
                                                                         constant:100];
    widthConstraint.priority = NSLayoutPriorityDefaultLow;
    [NSLayoutConstraint activateConstraints:@[leadingConstraint, topConstraint, widthConstraint, heightConstraint]];
    self.mainView.wantsLayer = YES;
    self.mainView.layer.backgroundColor = [NSColor redColor].CGColor;
#endif
}

@end

通过上述代码,在iOS和macOS上都实现了一个红色视图,距离父视图左上角20像素,宽度200像素,高度100像素,并且宽度约束优先级较低,以适应不同平台的布局差异。