标签:
开发中常见错误和警告总结(七)
CGPoint randomPoint()
{
int half = 32;
int freesize = 240 - 2 * half;
return CGPointMake(random() % freesize + half, random() % freesize + half);
}
warning:No previous prototype for function "randomPoint"。如何取消这个警告错误呢?方法尝试了这两种都可以:
2:使用Reachability的问题) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress;
做ios网络开发的肯定会用到苹果的官方库Reachability。warning:
1 + (Reachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress;
中
Declaration of ‘struct sockaddr_in‘ will not be visible outside of this function
解决办法很简单,Reachability.h中最前面添加头文件:#import <netinet/in.h>
有个小需求,需要遍历当前导航控制器栈的所有ViewController。UINavigationController类自身的viewControllers属性返回的是一个[AnyObject]!数组,不过由于我的导航控制器本身有可能是nil,所以我获取到的ViewController数组如下:
var myViewControllers: [AnyObject]? = navigationController?.viewControllers
获取到的myViewControllers是一个[AnyObject]?可选类型,这时如果我直接去遍历myViewControllers,如下代码所示
for controller in myViewControllers {
...
}
编译器会报错,提示如下:
[AnyObject]? does not have a member named "Generator"
实际上,不管是[AnyObject]?还是其它的诸如[String]?类型,都会报这个错。其原因是可选类型只是个容器,它与其所包装的值是不同的类型,也就是说[AnyObject]是一个数组类型,但[AnyObject]?并不是数组类型。我们可以迭代一个数组,但不是迭代一个非集合类型。
在stackoverflow上有这样一个有趣的比方,我犯懒就直接贴出来了:
To understand the difference, let me make a real life example: you buy a new TV on ebay, the package is shipped to you, the first thing you do is to check if the package (the optional) is empty (nil). Once you verify that the TV is inside, you have to unwrap it, and put the box aside. You cannot use the TV while it‘s in the package. Similarly, an optional is a container: it is not the value it contains, and it doesn‘t have the same type. It can be empty, or it can contain a valid value.
用Xcode 7 beta 3在真机(iOS 8.3)上运行一下我们的工程,结果发现工程编译不过。看了下问题,报的是以下错误:
ld: ‘/Users
/**/
Framework/SDKs/PolymerPay/Library/mobStat/lib**SDK.a(**ForSDK.o)’ does not contain bitcode. You must rebuild it
with
bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode
for
this
target.
for
architecture arm64
bitcode是被编译程序的一种中间形式的代码。包含bitcode配置的程序将会在App store上被编译和链接。bitcode允许苹果在后期重新优化我们程序的二进制文件,而不需要我们重新提交一个新的版本到App store上。
要么让第三方库支持,要么关闭target的bitcode选项。
实际上在Xcode 7中,我们新建一个iOS程序时,bitcode选项默认是设置为YES的。我们可以在”Build Settings”->”Enable Bitcode”选项中看到这个设置。
开发中常见错误和警告总结(十)
混编常见错误:
把 Swift 和 Objective-C 文件看作相同的代码集合,并注意命名冲突。
如果你使用了框架,确保在Packaging下的Defines Module编译设置被设置为 Yes。
如果你使用了 Objective-C 桥接头文件,确保 Swift 编译器中 Objective-C 桥接头文件的编译设置Code Generation有一个与项目相关的头文件的路径。这个路径必须是头文件自身的路径,而不是它所在的目录。
Xcode 使用你的工程模块名,而不是以target的名称来命名 Objective-C 桥接头文件以及为 Swift 代码 自动生成的头文件。详见 Naming Your Product Module。
为了在 Objective-C 中可用, Swift 类必须是 Objective-C 类的子类,或者用 @objc 标记。
当你将 Swift 导入到 Objective-C 中时,记住 Objective-C 不会将 Swift 独有的特性转化成 Objective-C 对应的特性。详见列表 Using Swift from Objective-C。
如果你在 Swift 代码中使用你自己的 Objective-C 类型,确保先将对应的 Objective-C 头文件导入到你的 Swift 代码中,然后才将 Swift 自动生成的头文件导入到 Objective-C .m 源文件中来访问 Swift 代码。
用private修饰符标记的 Swift 声明不会出现在自动生成的头文件中。私有声明不会暴漏给 Objective-C,除非它们被明确标记有@IBAction,@IBOutlet或者@objc等。
对于应用 targets 而言,如果有 Objective-C 桥接头文件时,被internal修饰符标记的声明会出现在自动产生的头文件中。
对于框架 targets 而言,只有被public修饰符标记的声明才会出现在自动生成的头文件中。你仍然可以在框架中的 Objective-C 部分使用被internal修饰符标记的 Swift 方法和属性,只要它们声明所在的类继承自 Objective-C 类。关于访问级别修饰符的更多信息,请查看The Swift Programming Language中的访问控制(Access Control)
开发中常见错误和警告总结(十一)
iOS资源按需加载:
启用按需加载资源
对于支持iOS 9.0及以后的app,按需加载资源是默认开启的。你也可以在target的build settings中手动更改。
启用或关闭按需加载资源:
在project navigator中选择工程文件。
在project editor中选择对应的target。
选择Build Settings选项卡。
展开Assets分类。
提示:可以在Build Settings选项卡右上角的搜索框中输入“Assets”,来快速定位到Assets分类。
设置Enable On-Demand Resources的值。
Yes为这个target开启按需加载资源。
No为这个target关闭按需加载资源。
开发中常见错误和警告总结(十二)
混编总结
Swift与Objective-c的代码相互调用,并不像Objective-c与C/C++那样方便,需要做一些额外的配置工作。无论是Swift调用Objective-c还是Objective-c调用Swift,Xcode在处理上都需要两个步骤:
Swift调用Objective-c代码
Xcode对于Swift调用Objective-c代码,除宏定义外,其它支持相对完善。
使用Objetvie-c的第一步
告诉Xcode、哪些Objective-c类要使用,新建.h头文件,文件名可以任意取,建议采用“项目名-Bridging-Header.h”命令格式。
Tips
Swift之IOS项目,在Xcode6创建类文件,默认会自动选择OS X标签下的文件,这时一定要选择iOS标签下的文件,否则会出现语法智能提示不起作用,严重时会导致打包出错。
第二步,Target配置,使创建的头文件生效
设置Objective-C Bridging Header时,路径要配置正确,例如:创建的名为“ILSwift-Bridging-Header.h”文件,存于ILSwift项目文件夹的根目录下,写法如下:
ILSwift/ILSwift-Bridging-Header.h
当然,在新项目中,直接创建一个Objective-c类,Xcode会提示:
直接选择Yes即可,如果不小心点了其它按钮,可以按照上面的步骤一步一步添加。
开发中常见错误和警告总结(十三)
混编总结
Objective-c调用Swift代码
Objective-c调用Swift代码两个步骤
第一步告诉Xcode哪些类需要使用(继承自NSObject的类自动处理,不需要此步骤),通过关键字@objc(className)来标记
1 import UIKit
2 @objc(ILWriteBySwift)
3 class ILWriteBySwift {
4 var name: String!
5 class func newInstance() -> ILWriteBySwift {
6 return ILWriteBySwift()
7 }
8 }
第二步引入头文件,Xcode头文件的命名规则为
示例如下:
#import "ILSwift-Swift.h"
不清楚SWIFT_MODULE_NAME可通过以下步骤查看
找不到$(SWIFT_MODULE_NAME)-Swift.h
1.遇到此问题可按以下步骤做常规性检查
确定导入SWIFT_MODULE_NAME)-Swift.h头文件的文件名正确
SWIFT_MODULE_NAME)-Swift.h在clean后没有重新构建,执行Xcode->Product->Build
2.头文件循环
在混合编程的项目中,由于两种语言的同时使用,经常会出现以下需求:在Swift项目中需要使用Objectvie-c写的A类,而A类又会用到Swift的一些功能,头文件的循环,导致编译器不能正确构建$(SWIFT_MODULE_NAME)-Swift.h,遇到此问题时,在.h文件做如下处理
//删除以下头文件
//#import "ILSwift-Swift.h"
//通过代码导入类
@class ILSwiftBean;
在Objevtive-c的.m文件最上面,添加
#import "ILSwift-Swift.h"
出现Use of undecalared identifier错误或者找不到方法,如下:
引起的原因有以下几种可能:
使用的Swift类不是继承自NSObject,加入关键字即可
SWIFT_MODULE_NAME)-Swift.h没有实时更新,Xcode->Product->Build
此Swift文件中使用了Objective-c不支持的类型或者语法,如private
出现部分方法找不到的问题,Xcode无智能提示:
此方法使用了Objective-c不支持的类型或者语法
苹果官方给出的不支持转换的类型
Generics
Tuples
Enumerations defined in Swift
Structures defined in Swift
Top-level functions defined in Swift
Global variables defined in Swift
Typealiases defined in Swift
Swift-style variadics
Nested types
Curried functions
开发中常见错误和警告总结(十四)
第三方类库支持
Swift项目取消了预编译文件,一些第三方Objective-c库没有导入必要框架(如UIKit)引起编译错误
Cocoapods找不到.o文件
在使用了Cocoapods项目中,会出现部分类库的.o文件找不到,导致此种错误主要是以下两种问题:
类库本身存在编译错误
Swift没有预编译,UIKit等没有导入
将此库文件中的代码文件直接加到项目中,编译,解决错误。
JSONModel支持
在Swift中可以使用JSONModel部分简单功能,一些复杂的数据模型建议使用Objevtive-c
1 import UIKit
2 @objc(ILLoginBean)
3 public class ILLoginBean: JSONModel {
4 var userAvatarURL: NSString?
5 var userPhone: NSString!
6 var uid: NSString!
7 }
Tips
在Swift使用JSONModel框架时,字段只能是NSFoundation中的支持类型,Swift下新添加的String、Int、Array等都不能使用
友盟统计
Swift项目中引入友盟统计SDK会出现referenced from错误:
解决办法,找到Other Linker Flags,添加-lz
开发中常见错误和警告总结(十五)
多Target编译错误解决
在使用多Target时,会出现一些编译错误
Use of undeclared type
此类错误,是因为当前运行的Target找不到必须编译文件。将文件添加到Target即可,如下支持ILSwiftTests Target,选中ILSwiftTests前的复选框即可
does not have a member named
此类错误可能由于如下两种原因引起,解决办法同上:
Tips
如果检查发现,所有的类文件都已经准确添加到Target中,但编译还是不通过,此时着重检查桥接文件是否正确设置,是否将相应的头文件加入到了桥接文件中。如无特别要求,建议将所有Target的桥接文件全都指向同一文件。关于桥接文件的设置,
开发中常见错误和警告总结(十六)
Objective-c巧妙调用不兼容的Swift方法
在Objective-c中调用Swift类中的方法时,由于部分Swift语法不支持转换,会遇到无法找到对应方法的情况,如下:
1 import UIKit
2 enum HTTPState {
3 case Succed, Failed, NetworkError, ServerError, Others
4 }
5 class ILHTTPRequest: NSObject {
6 class func requestLogin(userName: String, password: String, callback: (state: HTTPState) -> (Void)) {
7 dispatch_async(dispatch_get_global_queue(0, 0), { () -> Void in
8 NSThread.sleepForTimeInterval(3)
9 dispatch_async(dispatch_get_main_queue(), { () -> Void in
10 callback(state: HTTPState.Succed)
11 })
12 })
13 }
14 }
对应的$(SWIFT_MODULE_NAME)-Swift.h文件为:
1 SWIFT_CLASS("_TtC12ILSwiftTests13ILHTTPRequest")
2 @interface ILHTTPRequest : NSObject
3 - (SWIFT_NULLABILITY(nonnull) instancetype)init OBJC_DESIGNATED_INITIALIZER;
4 @end
从上面的头文件中可以看出,方法requestLogin使用了不支持的Swift枚举,转换时方法被自动忽略掉,有以下两种办法,可以巧妙解决类似问题:
用支持的Swift语法包装
在Swift文件中,添加一个可兼容包装方法wrapRequestLogin,注意此方法中不能使用不兼容的类型或者语法
1 import UIKit
2 enum HTTPState: Int {
3 case Succed = 0, Failed = 1, NetworkError = 2, ServerError = 3, Others = 4
4 }
5 class ILHTTPRequest: NSObject {
6 class func requestLogin(userName: String, password: String, callback: (state: HTTPState) -> (Void)) {
7 dispatch_async(dispatch_get_global_queue(0, 0), { () -> Void in
8 NSThread.sleepForTimeInterval(3)
9 dispatch_async(dispatch_get_main_queue(), { () -> Void in
10 callback(state: HTTPState.Succed)
11 })
12 })
13 }
14 class func wrapRequestLogin(userName: String, password: String, callback: (state: Int) -> (Void)) {
15 self.requestLogin(userName, password: password) { (state) -> (Void) in
16 callback(state: state.rawValue)
17 }
18 }
19 }
对应的$(SWIFT_MODULE_NAME)-Swift.h文件为:
1 SWIFT_CLASS("_TtC12ILSwiftTests13ILHTTPRequest")
2 @interface ILHTTPRequest : NSObject
3 + (void)wrapRequestLogin:(NSString * __nonnull)userName password:(NSString * __nonnull)password callback:(void (^ __nonnull)(NSInteger))callback;
4 - (SWIFT_NULLABILITY(nonnull) instancetype)init OBJC_DESIGNATED_INITIALIZER;
5 @end
此时,我们可以在Objective-c中直接使用包装后的方法wrapRequestLogin
巧妙使用继承
使用继承可以支持所有的Swift类型,主要的功能在Objective-c中实现,不支持的语法在Swift文件中调用,例如,ILLoginSuperController做为父类
1 @interface ILLoginSuperController : UIViewController
2 @property (weak, nonatomic) IBOutlet UITextField *userNameField;
3 @property (weak, nonatomic) IBOutlet UITextField *passwordField;
4 - (IBAction)loginButtonPressed:(id)sender;
5 @end
6 ////////////////////////////////////////////////////////////////
7 @implementation ILLoginSuperController
8 - (IBAction)loginButtonPressed:(id)sender
9 {
10 }
11 @end
创建Swift文件,继承自ILLoginSuperController,在此Swift文件中调用那些不支持的语法
1 import UIKit
2 class ILLoginController: ILLoginSuperController {
3 override func loginButtonPressed(sender: AnyObject!) {
4 ILHTTPRequest.requestLogin(self.userNameField.text, password: self.passwordField.text) { (state) -> (Void) in
5 //具体业务逻辑
6 }
7 }
8 }
开发中常见错误和警告总结(十八)
Xib/StoryBoard支持
Swift项目在使用Xib/StoryBoard时,会遇到两种不同的问题
Xib:不加载视图内容
Storyboard:找不到类文件
Xib不加载视图内容
在创建UIViewController时,默认选中Xib文件,在Xib与类文件名一致时,可通过以下代码实例化:
let controller = ILViewController()
运行,界面上空无一物,Xib没有被加载。解决办法,在类的前面加上@objc(类名),例如:
import UIKit
@objc(ILViewController)
class ILViewController: UIViewController {
}
Tips:
StoryBoard中创建的UIViewController,不需要@objc(类名)也能够保持兼容
Storyboard找不到类文件
Swift语言引入了Module概念,在通过关键字@objc(类名)做转换的时候,由于Storboard没有及时更新Module属性,会导致如下两种类型错误:
用@objc(类名)标记的Swift类或者Objective-c类可能出现错误:
2015-06-02 11:27:42.626 ILSwift[2431:379047] Unknown class _TtC7ILSwift33ILNotFindSwiftTagByObjcController in Interface Builder file.
解决办法,按下图,选中Module中的空白,直接回车
无@objc(类名)标记的Swift类
2015-06-02 11:36:29.788 ILSwift[2719:417490] Unknown class ILNotFindSwiftController in Interface Builder file.
解决办法,按下图,选择正确的Module
3.产生上面错误的原因: 在设置好Storyboard后,直接在类文件中,添加或者删除@objc(类名)关键字,导致Storyboard中 Module属性没有自动更新,所以一个更通用的解决办法是,让Storyboard自动更新Module,如下:
错误模拟Demo下载
为了能够让大家更清楚的了解解决流程,将上面的错误进行了模拟,想动手尝试解决以上问题的同学可以直接下载demo
标签:
原文地址:http://www.cnblogs.com/CoderAlex/p/4762206.html