MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Objective-C 在 iOS 界面设计中的运用技巧

2023-11-105.6k 阅读

一、Objective-C 在 iOS 界面设计基础概述

1.1 iOS 界面设计理念与 Objective-C 的契合

iOS 的界面设计以简洁、直观、易用为核心原则。Objective - C 作为 iOS 开发长期以来的主要编程语言,能够很好地适配这种设计理念。它的面向对象特性使得开发者可以将界面元素封装成对象,方便管理和操作。例如,一个按钮在 Objective - C 中可以被创建为 UIButton 对象,开发者能够通过该对象的属性和方法来定制按钮的外观、行为等,这种对象化的处理方式与 iOS 界面设计中对单个元素精细控制的要求高度契合。

1.2 视图层次结构与 Objective - C 实现

iOS 界面是基于视图层次结构构建的。最顶层的是 UIWindow,它包含了应用程序的所有可见内容。在 UIWindow 之下是各种 UIView 及其子类。Objective - C 通过创建和管理这些视图对象来搭建界面。比如,要创建一个简单的视图控制器,并在其视图上添加一个子视图,可以如下实现:

#import <UIKit/UIKit.h>

@interface MyViewController : UIViewController

@end

@implementation MyViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // 创建一个红色的矩形视图
    UIView *redView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
    redView.backgroundColor = [UIColor redColor];
    // 将红色视图添加到当前视图控制器的视图上
    [self.view addSubview:redView];
}

@end

在上述代码中,MyViewController 继承自 UIViewController,在 viewDidLoad 方法中创建了一个 UIView 对象并设置其背景颜色为红色,最后添加到视图控制器的视图上。这种通过代码创建视图并构建视图层次的方式是 iOS 界面设计中常用的手段,Objective - C 提供了清晰且易于理解的语法来实现这一过程。

二、视图与视图控制器的运用技巧

2.1 视图的布局技巧

2.1.1 基于 Frame 的布局

在早期的 iOS 开发中,基于 Frame 的布局是一种常用的方式。通过设置视图的 frame 属性来确定其在父视图中的位置和大小。例如,要在屏幕中心创建一个正方形按钮:

UIButton *centerButton = [UIButton buttonWithType:UIButtonTypeSystem];
centerButton.frame = CGRectMake((self.view.bounds.size.width - 100) / 2, (self.view.bounds.size.height - 100) / 2, 100, 100);
[centerButton setTitle:@"Click Me" forState:UIControlStateNormal];
[self.view addSubview:centerButton];

这里通过计算屏幕的宽度和高度,将按钮放置在屏幕中心。然而,这种方式在面对不同设备屏幕尺寸时需要手动调整 frame 的值,不够灵活。

2.1.2 自动布局(Auto Layout)

为了解决不同屏幕尺寸适配问题,iOS 引入了自动布局。在 Objective - C 中,可以通过 NSLayoutConstraint 类来创建约束。例如,要创建一个在父视图中心水平和垂直居中的视图:

UIView *centeredView = [[UIView alloc] init];
centeredView.backgroundColor = [UIColor blueColor];
[self.view addSubview:centeredView];

// 添加水平居中约束
NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:centeredView
                                                                   attribute:NSLayoutAttributeCenterX
                                                                   relatedBy:NSLayoutRelationEqual
                                                                      toItem:self.view
                                                                   attribute:NSLayoutAttributeCenterX
                                                                  multiplier:1.0
                                                                    constant:0];
// 添加垂直居中约束
NSLayoutConstraint *centerYConstraint = [NSLayoutConstraint constraintWithItem:centeredView
                                                                   attribute:NSLayoutAttributeCenterY
                                                                   relatedBy:NSLayoutRelationEqual
                                                                      toItem:self.view
                                                                   attribute:NSLayoutAttributeCenterY
                                                                  multiplier:1.0
                                                                    constant:0];

// 添加宽度和高度约束
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:centeredView
                                                                  attribute:NSLayoutAttributeWidth
                                                                  relatedBy:NSLayoutRelationEqual
                                                                     toItem:nil
                                                                  attribute:NSLayoutAttributeNotAnAttribute
                                                                 multiplier:1.0
                                                                   constant:150];
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:centeredView
                                                                   attribute:NSLayoutAttributeHeight
                                                                   relatedBy:NSLayoutRelationEqual
                                                                      toItem:nil
                                                                   attribute:NSLayoutAttributeNotAnAttribute
                                                                  multiplier:1.0
                                                                    constant:150];

// 将约束添加到父视图
[self.view addConstraints:@[centerXConstraint, centerYConstraint, widthConstraint, heightConstraint]];
// 激活自动布局
centeredView.translatesAutoresizingMaskIntoConstraints = NO;

上述代码通过创建水平、垂直居中以及宽度和高度的约束,使得 centeredView 能够在不同屏幕尺寸下都保持在父视图中心且具有固定大小。自动布局极大地提高了界面在不同设备上的适配性,Objective - C 提供了丰富的 API 来实现复杂的自动布局需求。

2.2 视图控制器的切换与管理

2.2.1 模态视图控制器

模态视图控制器是一种常见的视图控制器切换方式,它会覆盖当前视图控制器的部分或全部内容。例如,在应用中显示一个登录界面通常会使用模态视图控制器。创建并显示模态视图控制器的代码如下:

LoginViewController *loginVC = [[LoginViewController alloc] init];
[self presentViewController:loginVC animated:YES completion:nil];

在上述代码中,LoginViewController 是自定义的视图控制器,通过 presentViewController:animated:completion: 方法将其以模态方式呈现,animated:YES 表示切换过程有动画效果,completion:nil 是切换完成后的回调块,这里设置为 nil。当登录完成后,可以通过以下代码关闭模态视图控制器:

[self dismissViewControllerAnimated:YES completion:nil];

2.2.2 导航控制器

导航控制器用于管理一系列具有层次关系的视图控制器,通常用于实现类似树形结构的界面导航。例如,在一个新闻应用中,从新闻列表页面点击进入新闻详情页面就可以通过导航控制器来实现。首先创建一个导航控制器,并将根视图控制器设置为新闻列表视图控制器:

NewsListViewController *newsListVC = [[NewsListViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:newsListVC];
[self.window setRootViewController:navController];

当用户点击新闻列表中的某条新闻时,跳转到新闻详情视图控制器:

NewsDetailViewController *newsDetailVC = [[NewsDetailViewController alloc] init];
[self.navigationController pushViewController:newsDetailVC animated:YES];

这里通过 pushViewController:animated: 方法将新闻详情视图控制器压入导航栈,用户可以通过导航栏上的返回按钮返回新闻列表页面,导航控制器会自动管理视图控制器的切换和导航栈的操作。

三、界面交互设计技巧

3.1 按钮与手势交互

3.1.1 按钮的事件处理

按钮是 iOS 界面中最常见的交互元素之一。在 Objective - C 中,为按钮添加点击事件处理非常简单。例如,有一个按钮,当用户点击时显示一个提示框:

UIButton *alertButton = [UIButton buttonWithType:UIButtonTypeSystem];
alertButton.frame = CGRectMake(100, 200, 200, 50);
[alertButton setTitle:@"Show Alert" forState:UIControlStateNormal];
[alertButton addTarget:self action:@selector(showAlert) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:alertButton];

- (void)showAlert {
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Alert"
                                                                         message:@"You clicked the button!"
                                                                  preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
    [alertController addAction:okAction];
    [self presentViewController:alertController animated:YES completion:nil];
}

在上述代码中,通过 addTarget:action:forControlEvents: 方法为按钮的 UIControlEventTouchUpInside 事件(即手指抬起离开按钮时触发)添加了一个目标方法 showAlert。当按钮被点击时,会执行 showAlert 方法,显示一个提示框。

3.1.2 手势识别

除了按钮,手势识别也是常见的交互方式。例如,为视图添加一个点击手势识别:

UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapHandler)];
[self.view addGestureRecognizer:tapGesture];

- (void)tapHandler {
    NSLog(@"View was tapped!");
}

上述代码创建了一个 UITapGestureRecognizer 手势识别器,并将其添加到视图上,当视图被点击时,会调用 tapHandler 方法,在控制台输出日志。还可以创建其他类型的手势识别器,如滑动手势(UISwipeGestureRecognizer)、捏合手势(UIPinchGestureRecognizer)等,通过不同的手势识别来实现丰富的交互效果。

3.2 文本输入与键盘交互

3.2.1 文本框的使用

文本框(UITextField)是用于用户输入文本的常见控件。创建一个文本框并设置其代理来处理文本输入相关事件的代码如下:

UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(50, 150, 200, 30)];
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.placeholder = @"Enter text here";
textField.delegate = self;
[self.view addSubview:textField];

#pragma mark - UITextFieldDelegate methods
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    [textField resignFirstResponder];
    return YES;
}

在上述代码中,创建了一个带有圆角边框和占位文本的文本框,并将当前视图控制器设置为其代理。通过实现 UITextFieldDelegate 协议中的 textFieldShouldReturn: 方法,当用户点击键盘上的回车键时,使文本框放弃第一响应者状态,即收起键盘。

3.2.2 键盘的显示与隐藏控制

有时需要根据用户操作手动显示或隐藏键盘。例如,在一个搜索界面,点击搜索按钮时隐藏键盘:

UIButton *searchButton = [UIButton buttonWithType:UIButtonTypeSystem];
searchButton.frame = CGRectMake(260, 150, 50, 30);
[searchButton setTitle:@"Search" forState:UIControlStateNormal];
[searchButton addTarget:self action:@selector(searchButtonTapped) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:searchButton];

- (void)searchButtonTapped {
    [self.view endEditing:YES];
}

在上述代码中,searchButtonTapped 方法通过调用 [self.view endEditing:YES] 来使视图及其子视图中的所有第一响应者放弃第一响应者状态,从而隐藏键盘。还可以通过监听键盘的显示和隐藏通知来实现更复杂的界面调整,例如当键盘显示时,将视图向上移动以避免遮挡输入框。

四、自定义界面元素技巧

4.1 自定义视图

4.1.1 继承 UIView 进行自定义

通过继承 UIView 类,可以创建具有独特外观和行为的自定义视图。例如,创建一个圆形进度条视图:

#import <UIKit/UIKit.h>

@interface CircularProgressView : UIView

@property (nonatomic, assign) CGFloat progress;

@end

@implementation CircularProgressView

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGFloat centerX = CGRectGetMidX(rect);
    CGFloat centerY = CGRectGetMidY(rect);
    CGFloat radius = MIN(rect.size.width, rect.size.height) / 2 - 5;

    CGContextSetLineWidth(context, 10);
    CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
    CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor);

    CGFloat startAngle = - M_PI_2;
    CGFloat endAngle = startAngle + (self.progress * 2 * M_PI);

    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(centerX, centerY)
                                                        radius:radius
                                                    startAngle:startAngle
                                                      endAngle:endAngle
                                                     clockwise:YES];
    [path setLineWidth:10];
    [path stroke];
}

@end

在上述代码中,CircularProgressView 继承自 UIView,通过重写 drawRect: 方法,使用 Core Graphics 绘制了一个圆形进度条。在使用时,可以如下设置进度值并添加到视图中:

CircularProgressView *progressView = [[CircularProgressView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
progressView.progress = 0.5;
[self.view addSubview:progressView];

4.1.2 使用 Interface Builder 与自定义视图结合

除了纯代码创建自定义视图,还可以结合 Interface Builder 来提高开发效率。首先在 Interface Builder 中创建一个视图,将其类设置为自定义视图类,然后可以在自定义视图类的代码中通过 @IBOutlet 连接视图中的子视图,并进行进一步的定制。例如,在自定义视图中有一个标签用于显示进度值:

#import <UIKit/UIKit.h>

@interface CircularProgressView : UIView

@property (nonatomic, assign) CGFloat progress;
@property (weak, nonatomic) IBOutlet UILabel *progressLabel;

@end

@implementation CircularProgressView

- (void)drawRect:(CGRect)rect {
    // 绘制圆形进度条代码...
}

- (void)setProgress:(CGFloat)progress {
    _progress = progress;
    self.progressLabel.text = [NSString stringWithFormat:@"%.0f%%", progress * 100];
    [self setNeedsDisplay];
}

@end

在 Interface Builder 中,将标签与 progressLabel 属性连接起来,这样当进度值改变时,标签会自动更新显示进度百分比。

4.2 自定义视图控制器

4.2.1 自定义视图控制器的布局与行为

通过继承 UIViewController,可以创建具有独特布局和行为的自定义视图控制器。例如,创建一个具有左右滑动切换视图功能的自定义视图控制器:

#import <UIKit/UIKit.h>

@interface SlideViewController : UIViewController <UIScrollViewDelegate>

@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) NSArray *viewControllers;

@end

@implementation SlideViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
    self.scrollView.pagingEnabled = YES;
    self.scrollView.delegate = self;
    self.scrollView.showsHorizontalScrollIndicator = NO;
    [self.view addSubview:self.scrollView];

    UIViewController *firstVC = [[UIViewController alloc] init];
    firstVC.view.backgroundColor = [UIColor redColor];
    [self addChildViewController:firstVC];
    [self.scrollView addSubview:firstVC.view];

    UIViewController *secondVC = [[UIViewController alloc] init];
    secondVC.view.backgroundColor = [UIColor blueColor];
    [self addChildViewController:secondVC];
    [self.scrollView addSubview:secondVC.view];

    self.viewControllers = @[firstVC, secondVC];

    CGFloat width = self.view.bounds.size.width;
    for (NSInteger i = 0; i < self.viewControllers.count; i++) {
        UIViewController *vc = self.viewControllers[i];
        vc.view.frame = CGRectMake(i * width, 0, width, self.view.bounds.size.height);
    }
    self.scrollView.contentSize = CGSizeMake(width * self.viewControllers.count, self.view.bounds.size.height);
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    CGFloat pageWidth = scrollView.frame.size.width;
    NSInteger page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
    UIViewController *vc = self.viewControllers[page];
    [self setValue:vc forKey:@"childViewControllers"];
}

@end

在上述代码中,SlideViewController 继承自 UIViewController,通过创建一个 UIScrollView 并添加多个子视图控制器来实现左右滑动切换视图的功能。在 scrollViewDidScroll: 方法中,根据滚动的位置来更新当前显示的子视图控制器。

4.2.2 自定义视图控制器的过渡动画

可以为自定义视图控制器的切换添加过渡动画。例如,实现一个淡入淡出的过渡动画:

@interface FadeTransitioningDelegate : NSObject <UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate>

@end

@implementation FadeTransitioningDelegate

- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
    return 0.5;
}

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIView *containerView = [transitionContext containerView];

    [containerView addSubview:toVC.view];
    toVC.view.alpha = 0;

    [UIView animateWithDuration:[self transitionDuration:transitionContext]
                          delay:0
                        options:UIViewAnimationOptionCurveEaseInOut
                     animations:^{
                         fromVC.view.alpha = 0;
                         toVC.view.alpha = 1;
                     }
                     completion:^(BOOL finished) {
                         [fromVC.view removeFromSuperview];
                         [transitionContext completeTransition:!transitionContext.transitionWasCancelled];
                     }];
}

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented
                                                                  presentingController:(UIViewController *)presenting
                                                                      sourceController:(UIViewController *)source {
    return self;
}

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
    return self;
}

@end

在使用时,将自定义视图控制器的 transitioningDelegate 属性设置为 FadeTransitioningDelegate 的实例,即可实现淡入淡出的过渡动画:

FadeTransitioningDelegate *delegate = [[FadeTransitioningDelegate alloc] init];
MyCustomViewController *customVC = [[MyCustomViewController alloc] init];
customVC.transitioningDelegate = delegate;
customVC.modalPresentationStyle = UIModalPresentationCustom;
[self presentViewController:customVC animated:YES completion:nil];

五、优化 iOS 界面性能的技巧

5.1 减少视图层级嵌套

视图层级嵌套过多会增加渲染的复杂度和性能开销。在设计界面时,应尽量减少不必要的视图嵌套。例如,原本为了实现一个简单的图文组合,可能会创建多层视图嵌套:

// 不合理的多层嵌套
UIView *outerView = [[UIView alloc] init];
UIView *middleView = [[UIView alloc] init];
UILabel *textLabel = [[UILabel alloc] init];
UIImageView *imageView = [[UIImageView alloc] init];

[outerView addSubview:middleView];
[middleView addSubview:textLabel];
[middleView addSubview:imageView];

而可以通过合理布局,减少一层视图嵌套:

// 优化后的布局
UIView *containerView = [[UIView alloc] init];
UILabel *textLabel = [[UILabel alloc] init];
UIImageView *imageView = [[UIImageView alloc] init];

[containerView addSubview:textLabel];
[containerView addSubview:imageView];

这样不仅减少了视图层级,还提高了布局的简洁性和性能。

5.2 图片处理与优化

5.2.1 图片加载优化

在 iOS 界面中,图片加载是一个常见的性能瓶颈。避免一次性加载过大的图片,可以根据设备屏幕分辨率加载合适尺寸的图片。例如,对于视网膜屏(Retina)设备,加载两倍分辨率的图片:

UIImage *image;
if ([UIScreen mainScreen].scale == 2) {
    image = [UIImage imageNamed:@"image@2x"];
} else {
    image = [UIImage imageNamed:@"image"];
}
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];

还可以使用图片加载框架,如 SDWebImageAFNetworking 的图片加载功能,它们具有图片缓存、异步加载等优化特性。以 SDWebImage 为例,加载网络图片:

#import <SDWebImage/UIImageView+WebCache.h>

UIImageView *imageView = [[UIImageView alloc] init];
NSURL *imageURL = [NSURL URLWithString:@"http://example.com/image.jpg"];
[imageView sd_setImageWithURL:imageURL];

5.2.2 图片渲染优化

对于需要在界面上频繁绘制的图片,如游戏中的角色动画图片,可以将图片处理为纹理格式,使用 OpenGL 等图形库进行渲染,以提高渲染效率。在 Objective - C 中,可以通过 GLKViewGLKBaseEffect 等类来实现简单的 OpenGL 渲染。例如,显示一张纹理图片:

#import <GLKit/GLKit.h>

@interface MyGLViewController : GLKViewController

@property (nonatomic, strong) GLKBaseEffect *baseEffect;
@property (nonatomic, assign) GLuint texture;

@end

@implementation MyGLViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.baseEffect = [[GLKBaseEffect alloc] init];
    self.baseEffect.useConstantColor = GL_TRUE;
    self.baseEffect.constantColor = GLKVector4Make(1.0, 1.0, 1.0, 1.0);

    UIImage *image = [UIImage imageNamed:@"textureImage"];
    CGImageRef cgImage = image.CGImage;
    GLsizei width = (GLsizei)CGImageGetWidth(cgImage);
    GLsizei height = (GLsizei)CGImageGetHeight(cgImage);
    GLubyte *imageData = (GLubyte *)calloc(width * height * 4, sizeof(GLubyte));
    CGContextRef context = CGBitmapContextCreate(imageData, width, height, 8, width * 4, CGImageGetColorSpace(cgImage), kCGImageAlphaPremultipliedLast);
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgImage);
    CGContextRelease(context);

    glGenTextures(1, &_texture);
    glBindTexture(GL_TEXTURE_2D, _texture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
    free(imageData);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);

    self.baseEffect.texture2d0.enabled = GL_TRUE;
    self.baseEffect.texture2d0.name = _texture;

    [self.baseEffect prepareToDraw];

    GLfloat vertices[] = {
        -1.0, -1.0, 0.0, 0.0, 1.0,
        1.0, -1.0, 0.0, 1.0, 1.0,
        1.0, 1.0, 0.0, 1.0, 0.0,
        -1.0, 1.0, 0.0, 0.0, 0.0
    };

    GLuint indices[] = {
        0, 1, 2,
        2, 3, 0
    };

    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vertices);

    glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), &vertices[3]);

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, indices);
}

@end

上述代码通过 OpenGL 将图片处理为纹理并进行渲染,相比直接使用 UIImageView 显示图片,在性能上有一定提升,尤其适用于对性能要求较高的场景。

5.3 内存管理与优化

5.3.1 避免内存泄漏

在 Objective - C 中,内存管理不当容易导致内存泄漏。例如,在视图控制器中创建了一个强引用的定时器,但在视图控制器销毁时没有停止定时器,就会导致视图控制器无法释放,造成内存泄漏:

@interface MemoryLeakViewController : UIViewController {
    NSTimer *timer;
}

@end

@implementation MemoryLeakViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
}

- (void)timerMethod {
    // 定时器执行的方法
}

- (void)dealloc {
    // 没有停止定时器,导致内存泄漏
    // [timer invalidate];
    // timer = nil;
}

@end

要避免这种情况,在 dealloc 方法中停止定时器并将其设置为 nil

- (void)dealloc {
    [timer invalidate];
    timer = nil;
}

5.3.2 自动释放池的合理使用

自动释放池(NSAutoreleasePool)可以帮助管理对象的内存释放时机。在循环中创建大量临时对象时,如果不使用自动释放池,可能会导致内存峰值过高。例如,以下代码在循环中创建大量字符串对象:

for (NSInteger i = 0; i < 100000; i++) {
    NSString *tempString = [NSString stringWithFormat:@"%ld", (long)i];
    // 对 tempString 进行一些操作
}

可以通过在循环内创建自动释放池来及时释放这些临时对象:

for (NSInteger i = 0; i < 100000; i++) {
    @autoreleasepool {
        NSString *tempString = [NSString stringWithFormat:@"%ld", (long)i];
        // 对 tempString 进行一些操作
    }
}

这样可以有效地降低内存峰值,提高应用的性能和稳定性。

通过以上在视图布局、交互设计、自定义元素以及性能优化等方面的技巧,开发者能够利用 Objective - C 在 iOS 界面设计中创建出更加美观、高效且用户体验良好的应用界面。不断熟练掌握和运用这些技巧,有助于提升 iOS 应用开发的质量和竞争力。