Xcode7 你不知道的事

本文详细介绍了Objective-C中轻量级泛型的使用方法及优势,包括带泛型的容器、自定义泛型类、协变性和逆变性、__kindof关键字等新特性,并通过代码示例展示了如何在实际开发中应用这些功能,旨在提升代码的清晰度和安全性。

Lightweight Generics 轻量级泛型,轻量是因为这是个纯编译器的语法支持(llvm 7.0),和 Nullability 一样,没有借助任何 objc runtime 的升级,也就是说,这个新语法在 Xcode 7 上可以使用且完全向下兼容(更低的 iOS 版本)

带泛型的容器

这无疑是本次最重大的改进,有了泛型后终于可以指定容器类中对象的类型了:

1
2
NSArray<NSString *> *strings = @[@"sun", @"yuan"];
NSDictionary<NSString *, NSNumber *> *mapping = @{@"a": @1, @"b": @2};

返回值的 id 被替换成具体的类型后,令人感动的代码提示也出来了:

假如向泛型容器中加入错误的对象,编译器会不开心的:

系统中常用的一系列容器类型都增加了泛型支持,甚至连 NSEnumerator 都支持了,这是非常 Nice 的改进。和 Nullability 一样,我认为最大的意义还是丰富了接口描述信息,对比下面两种写法:

1
2
@property (readonly) NSArray *imageURLs;
@property (readonly) NSArray<NSURL *> *imageURLs;

不用多想就清楚下面的数组中存的是什么,避免了 NSString 和 NSURL 的混乱。

自定义泛型类

比起使用系统的泛型容器,更好玩的是自定义一个泛型类,目前这里还没什么文档,但拦不住我们写测试代码,假设我们要自定义一个 Stack 容器类:

1
2
3
4
5
@interface Stack<ObjectType> : NSObject
- (void)pushObject:(ObjectType)object;
- (ObjectType)popObject;
@property (nonatomic, readonly) NSArray<ObjectType> *allObjects;
@end

这个 ObjectType 是传入类型的 placeholder,它只能在 @interface 上定义(类声明、类扩展、Category),如果你喜欢用 T 表示也 ok,这个类型在 @interface 和 @end 区间的作用域有效,可以把它作为入参、出参、甚至内部 NSArray 属性的泛型类型,应该说一切都是符合预期的。我们还可以给 ObjectType 增加类型限制,比如:

1
2
3
4
// 只接受 NSNumber * 的泛型
@interface Stack<ObjectType: NSNumber *> : NSObject
// 只接受满足 NSCopying 协议的泛型
@interface Stack<ObjectType: id<NSCopying>> : NSObject

若什么都不加,表示接受任意类型 ( id );当类型不满足时编译器将产生 error。
实例化一个 Stack,一切工作正常:

对于多参数的泛型,用逗号隔开,其他都一样,可以参考 NSDictionary 的头文件。

协变性和逆变性

当类支持泛型后,它们的 Type 发生了变化,比如下面三个对象看上去都是 Stack,但实际上属于三个 Type:

1
2
3
Stack *stack; // Stack *
Stack<NSString *> *stringStack; // Stack<NSString *>
Stack<NSMutableString *> *mutableStringStack; // Stack<NSMutableString *>

当其中两种类型做类型转化时,编译器需要知道哪些转化是允许的,哪些是禁止的,比如,默认情况下:

我们可以看到,不指定泛型类型的 Stack 可以和任意泛型类型转化,但指定了泛型类型后,两个不同类型间是不可以强转的,假如你希望主动控制转化关系,就需要使用泛型的协变性逆变性修饰符了:

__covariant - 协变性,子类型可以强转到父类型(里氏替换原则)
__contravariant - 逆变性,父类型可以强转到子类型(WTF?)

协变:

1
@interface Stack<__covariant ObjectType> : NSObject

效果:

逆变:

1
@interface Stack<__contravariant ObjectType> : NSObject

效果:

协变是非常好理解的,像 NSArray 的泛型就用了协变的修饰符,而逆变我还没有想到有什么实际的使用场景。

__kindof

__kindof 这修饰符还是很实用的,解决了一个长期以来的小痛点,拿原来的 UITableView 的这个方法来说:

1
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier;

使用时前面基本会使用 UITableViewCell 子类型的指针来接收返回值,所以这个 API 为了让开发者不必每次都蛋疼的写显式强转,把返回值定义成了 id 类型,而这个 API 实际上的意思是返回一个 UITableViewCell 或 UITableViewCell 子类的实例,于是新的 __kindof 关键字解决了这个问题:

1
- (__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier;

既明确表明了返回值,又让使用者不必写强转。再举个带泛型的例子,UIView 的 subviews 属性被修改成了:

1
@property (nonatomic, readonly, copy) NSArray<__kindof UIView *> *subviews;

这样,写下面的代码时就没有任何警告了:

1
UIButton *button = view.subviews.lastObject;

Where to go

有了上面介绍的这些新特性以及如 instancetype 这样的历史更新,Objective-C 这门古老语言的类型检测和类型推断终于有所长进,现在不论是接口还是代码中的 id 类型都越来越少,更多潜在的类型错误可以被编译器的静态检查发现。
同时,个人感觉新版的 Xcode 对继承链构造器的检测也加强了,NS_DESIGNATED_INITIALIZER 这个宏并不是新面孔,可以使用它标志出像 Swift 一样的指定构造器和便捷构造器。

最后,附上一段用上了所有新特性的代码,Swift 是发展趋势,如果你暂时依然要写 Objective-C 代码,把所有新特性都用上,或许能让你到新语言的迁移更无痛一点。

<think>我们正在处理用户关于Xcode编译后生成的framework文件找到的问题。根据引用[1]和引用[2]的信息,我们可以提供以下解决方案:1.**查找默认的DerivedData目录**:Xcode默认将编译生成的文件(包括framework)放在DerivedData目录中。可以通过以下方式找到:-打开Xcode,进入`Preferences`(偏好设置)-> `Locations`(位置)。-在`Derived Data`部分,如果设置的是`Default`(默认),则路径为:`~/Library/Developer/Xcode/DerivedData`。-如果设置的是`Custom`(自定义),则显示自定义路径。2. **在Derived Data目录中查找framework**:-打开终端,进入Derived Data目录(例如:`cd ~/Library/Developer/Xcode/DerivedData`)。-在该目录下,每个项目都有一个独立的文件夹(通常由项目名和随机字符串组成)。进入对应项目的文件夹。-然后进入`Build/Products`目录,再根据编译配置(Debug或Release)进入相应目录,即可找到生成的framework文件。 3. **使用查找命令**:如果知道framework的名称,可以使用终端命令进行查找。例如,查找名为`MyFramework.framework`的文件:```bashfind~/Library/Developer/Xcode/DerivedData -name "MyFramework.framework" -type d```或者在整个用户目录下查找(范围较大,可能较慢):```bashfind~-name"MyFramework.framework"-typed```4.**检查Xcode中的构建路径设置**:-在Xcode中,选择目标,进入`Build Settings`(构建设置)。-搜索`Per-configuration BuildProducts Path`(每个配置的构建产品路径)选项,查看自定义的构建路径。5.**检查framework的构建产物设置**:-确保在构建framework的scheme中,选择了正确的构建配置(Debug或Release)。-在构建完成后,Xcode有时会在Products组中显示生成的framework,右键点击可以在Finder中显示。6.**注意framework的构建平台**:如果构建的是iOS framework,并且使用了模拟器架构,那么生成的framework可能位于`Build/Products`下的`Debug-iphonesimulator`或`Release-iphonesimulator`目录。如果是真机架构,则位于`Debug-iphoneos`或`Release-iphoneos`目录。7.**使用Xcode的Showin Finder**:-在Xcode左侧的项目导航器中,展开`Products`文件夹。-右键点击你的`.framework`文件,选择`Show inFinder`。 8. **引用[2]中提到的注意项**:如果在构建framework时遇到链接错误,可能需要添加链接器标志`-ObjC`和`-all_load`。但这与查找文件位置无关,属于构建问题。如果按照以上步骤仍然找到,请检查:-是否成功构建了framework(构建过程中是否有错误)。-在Xcode的构建日志中,可以查看详细的输出路径(通过ReportNavigator查看构建日志,展开编译步骤,查看输出文件路径)。§§相关问题§§1.如何更改Xcode的Derived Data默认位置? 2.如何清理Xcode的Derived Data?3.如何合并同架构的framework(如模拟器和真机)?</think>### Xcode 编译后生成的 framework 文件找到:解决方法 根据引用内容,Xcode 生成的 framework 文件通常位于 **Derived Data 目录** 中。以下是具体解决步骤: --- #### 1. **定位 Derived Data 目录** - 打开 Xcode → `Preferences` (偏好设置) → `Locations` (位置) - 查看 `Derived Data` 路径: - 若设置为 `Default`:默认路径为 `/Users/你的用户名/Library/Developer/Xcode/DerivedData` - 若设置为 `Custom`:显示自定义路径 ![Xcode Derived Data 设置](https://help.apple.com/xcode/mac/current/en.lproj/Art/xc_pref_locations_pane_derived_data.png) *图:Xcode 中的 Derived Data 设置位置[^1]* --- #### 2. **手动查找 framework 文件** 在终端执行: ```bash # 进入 Derived Data 目录 cd ~/Library/Developer/Xcode/DerivedData # 查找所有 .framework 文件 find . -name "*.framework" -type d ``` - 文件通常位于: `项目名-随机字符串/Build/Products/` - 子目录说明: - **Debug-iphonesimulator**:模拟器版 framework - **Debug-iphoneos**:真机版 framework - **Release-**:发布版目录 --- #### 3. **通过 Xcode 直接定位** - 在项目导航器中,展开 `Products` 文件夹 - 右键点击 `.framework` 文件 → `Show in Finder` ![在 Finder 中显示 framework](https://miro.medium.com/v2/resize:fit:1400/1*9Q0qd1ySfS0f0b-C8d4L7Q.png) *图:通过 Xcode 直接定位文件[^2]* --- #### 4. **常见问题排查** | 问题 | 解决方法 | |------|----------| | **文件未生成** | 检查编译日志(Report Navigator → Build)是否有错误 | | **路径被自定义** | 在 `Xcode → Locations → Derived Data` 确认自定义路径 | | **多平台混淆** | 区分模拟器版(含 `simulator`)和真机版(含 `iphoneos`) | | **缓存问题** | 执行 `Xcode → Product → Clean Build Folder` 后重新编译 | --- #### 5. **引用说明** > “如果项目中使用文件 IO 创建文件,路径 `./result.txt` 的实际位置在 Derived Data 的子目录中,而非项目源代码目录”[^1]。 > 构建 framework 时若遇到链接错误,需在 `Other Linker Flags` 添加 `-ObjC -all_load`[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值