MST

星途 面试题库

面试题:Objective-C下复杂UI组件自定义与复用的架构设计

假设你要开发一个电商应用,其中商品展示模块有多种类型的UI组件,如商品卡片、筛选栏等,这些组件需要高度自定义且复用性强。请阐述你会如何设计整个UI组件的架构,包括类的继承关系、数据传递方式以及如何处理组件间的交互,并用Objective-C代码示例说明关键部分。
44.9万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

类的继承关系设计

  1. 基础组件类:创建一个基类 BaseComponent,它包含一些所有 UI 组件可能共有的属性和方法,例如 framebackgroundColor 等通用属性,以及 initWithFrame: 等初始化方法。
@interface BaseComponent : UIView
@property (nonatomic, assign) CGRect frame;
@property (nonatomic, strong) UIColor *backgroundColor;
- (instancetype)initWithFrame:(CGRect)frame;
@end

@implementation BaseComponent
- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        // 初始化操作
    }
    return self;
}
@end
  1. 商品卡片类:继承自 BaseComponent,并添加商品卡片特有的属性和方法,如商品图片、商品名称、价格等属性,以及设置这些属性的方法。
@interface ProductCard : BaseComponent
@property (nonatomic, strong) UIImage *productImage;
@property (nonatomic, strong) NSString *productName;
@property (nonatomic, assign) CGFloat price;
- (void)setProductImage:(UIImage *)image;
- (void)setProductName:(NSString *)name;
- (void)setPrice:(CGFloat)price;
@end

@implementation ProductCard
- (void)setProductImage:(UIImage *)image {
    _productImage = image;
    // 更新 UI 显示图片的逻辑
}
- (void)setProductName:(NSString *)name {
    _productName = name;
    // 更新 UI 显示名称的逻辑
}
- (void)setPrice:(CGFloat)price {
    _price = price;
    // 更新 UI 显示价格的逻辑
}
@end
  1. 筛选栏类:同样继承自 BaseComponent,添加筛选栏特有的属性和方法,比如筛选条件数组、筛选回调等。
@interface FilterBar : BaseComponent
@property (nonatomic, strong) NSArray *filterConditions;
@property (nonatomic, copy) void(^filterCallback)(NSArray *selectedFilters);
- (void)setFilterConditions:(NSArray *)conditions;
@end

@implementation FilterBar
- (void)setFilterConditions:(NSArray *)conditions {
    _filterConditions = conditions;
    // 更新 UI 显示筛选条件的逻辑
}
@end

数据传递方式

  1. 属性赋值:对于简单的数据,如商品卡片的图片、名称、价格等,通过直接设置属性来传递数据,如上述 ProductCard 类中的 setProductImage:setProductName:setPrice: 方法。
  2. 代理模式:当组件需要与外部进行交互时,可以使用代理模式。例如,筛选栏选择筛选条件后,通知外部处理筛选结果。
    • 定义代理协议
@protocol FilterBarDelegate <NSObject>
- (void)filterBar:(FilterBar *)filterBar didSelectFilters:(NSArray *)selectedFilters;
@end
- 在 `FilterBar` 类中添加代理属性
@interface FilterBar : BaseComponent
@property (nonatomic, weak) id<FilterBarDelegate> delegate;
// 其他属性和方法...
@end
- 在筛选操作完成后调用代理方法
@implementation FilterBar
// 筛选操作完成
- (void)finishFilter {
    NSArray *selectedFilters = // 获取选中的筛选条件
    if ([self.delegate respondsToSelector:@selector(filterBar:didSelectFilters:)]) {
        [self.delegate filterBar:self didSelectFilters:selectedFilters];
    }
}
@end
  1. 通知中心:对于一些全局的、不特定对象间的数据传递,可以使用通知中心。比如商品卡片的点击事件通知其他模块进行相应处理。
    • 发送通知
@implementation ProductCard
- (void)handleTap {
    NSDictionary *userInfo = @{@"product": self};
    [[NSNotificationCenter defaultCenter] postNotificationName:@"ProductCardTappedNotification" object:nil userInfo:userInfo];
}
@end
- 接收通知
@interface SomeOtherViewController : UIViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleProductCardTapNotification:) name:@"ProductCardTappedNotification" object:nil];
}
- (void)handleProductCardTapNotification:(NSNotification *)notification {
    ProductCard *productCard = notification.userInfo[@"product"];
    // 处理商品卡片点击后的逻辑
}
@end

组件间的交互处理

  1. 通过代理和通知:如上述代理模式和通知中心的示例,筛选栏通过代理通知外部处理筛选结果,商品卡片通过通知通知其他模块处理点击事件。
  2. 父子视图关系:如果商品卡片和筛选栏存在父子视图关系,可以通过父视图来协调它们之间的交互。例如,父视图监听筛选栏的筛选结果,然后根据结果更新商品卡片的展示。
@interface ProductListViewController : UIViewController <FilterBarDelegate>
@property (nonatomic, strong) FilterBar *filterBar;
@property (nonatomic, strong) NSMutableArray<ProductCard *> *productCards;
- (void)viewDidLoad {
    [super viewDidLoad];
    self.filterBar = [[FilterBar alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 44)];
    self.filterBar.delegate = self;
    [self.view addSubview:self.filterBar];
    // 初始化商品卡片数组并添加到视图
}
- (void)filterBar:(FilterBar *)filterBar didSelectFilters:(NSArray *)selectedFilters {
    // 根据筛选结果更新商品卡片的展示
    for (ProductCard *card in self.productCards) {
        // 判断卡片是否符合筛选条件,决定是否显示
    }
}
@end

通过上述设计,能够实现电商应用中商品展示模块 UI 组件的高度自定义和强复用性,同时有效处理组件间的交互。