面试题答案
一键面试设计思路
- 分层架构中运用类别:
- 数据层:可以为模型类添加类别来处理数据持久化相关的方法。例如,对于一个
User
模型类,创建User+CoreData
类别,在其中实现与Core Data交互的方法,如保存用户数据、从数据库读取用户数据等。这样可以将数据层的逻辑从主类中分离出来,使主类更加简洁,专注于业务逻辑。 - 业务逻辑层:为视图控制器添加类别来处理特定业务逻辑。比如,在一个电商应用中,
ProductViewController
可以有ProductViewController+CartLogic
类别,在该类别中实现将商品添加到购物车、从购物车移除商品等业务逻辑。这样即使业务逻辑复杂,也能保持视图控制器的清晰结构。 - 表示层:对于视图类,可以使用类别来添加一些外观相关的方法。例如,
UIButton
类可以有UIButton+CustomAppearance
类别,在其中定义设置按钮特定样式的方法,如设置按钮的背景色、字体、圆角等,使界面定制逻辑更加集中。
- 数据层:可以为模型类添加类别来处理数据持久化相关的方法。例如,对于一个
- 模块化设计中运用类别:
- 功能模块:假设项目中有一个社交分享模块,为
UIViewController
添加UIViewController+SocialSharing
类别,在类别中实现分享到不同平台(如微信、微博、Facebook等)的方法。这样每个功能模块可以通过类别封装相关功能,便于代码的复用和维护。不同的模块可以通过类别来提供对外接口,方便其他模块调用。 - 代码复用模块:如果项目中有一些通用的工具方法,比如日期处理、字符串处理等,可以为
NSObject
类添加类别,如NSObject+DateUtils
和NSObject+StringUtils
。这样在项目中的任何类都可以方便地调用这些工具方法,提高代码复用性。
- 功能模块:假设项目中有一个社交分享模块,为
潜在问题及解决方案
- 命名冲突:
- 问题:当多个类别为同一个类添加相同名称的方法时,会导致运行时的方法覆盖,可能出现难以调试的错误。
- 解决方案:
- 采用命名空间式的命名规则。例如,在类别的方法名前加上模块名或功能前缀。如
ProductViewController+CartLogic
类别中的方法命名为cart_addProduct:
而不是简单的addProduct:
。 - 在开发过程中,使用工具(如Clang静态分析工具)来检查是否存在命名冲突。定期对项目进行全面的代码检查,及时发现和解决潜在的命名冲突问题。
- 采用命名空间式的命名规则。例如,在类别的方法名前加上模块名或功能前缀。如
- 类的内部状态访问:
- 问题:类别无法直接访问类的私有实例变量。如果在类别中需要访问类的内部状态,可能会破坏类的封装性。
- 解决方案:
- 通过属性(Property)来间接访问内部状态。在类中定义属性,即使是私有的属性,也可以通过类别中的
@dynamic
关键字来声明访问器,从而间接访问内部状态。例如,类中有一个私有属性_privateData
,在类别中可以声明@property (nonatomic, strong) id privateData;
并使用@dynamic privateData;
,然后通过self.privateData
来访问。 - 可以在类中提供一些访问内部状态的公共方法,类别通过调用这些公共方法来操作内部状态,这样既能保持类的封装性,又能满足类别对内部状态的操作需求。
- 通过属性(Property)来间接访问内部状态。在类中定义属性,即使是私有的属性,也可以通过类别中的
- 类别的继承问题:
- 问题:类别本身不支持继承,如果需要在子类中复用类别中的方法,可能会遇到困难。
- 解决方案:
- 将通用的类别方法移到基类的类别中,这样子类也能继承这些方法。例如,如果有
UIViewController+CommonMethods
类别,其中的方法对于所有视图控制器子类都适用,就可以放在这个基类的类别中。 - 如果子类有特殊需求,可以在子类的类别中重写基类类别中的方法,但要注意保持方法的一致性和兼容性,避免出现意外的行为。
- 将通用的类别方法移到基类的类别中,这样子类也能继承这些方法。例如,如果有