Swift转Objective-C代码报错:URLComponents隐式声明无效
我在把一段Swift的App URL跳转处理代码转成Objective-C时遇到了编译错误,错误提示是Implicit declaration of function 'URLComponents' is invalid in C99。
我的Swift原代码:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { print(url) let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: true) let host = urlComponents?.host ?? "" print(host) return true }
我编写的Objective-C代码(报错版本):
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options { printf("%s", url); NSURLComponents * const urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: true); NSString * const host = urlComponents.host ?? "" printf(host); return true; }
错误原因及修正方案:
你的代码里踩了几个Objective-C和Swift语法差异的坑,一个个解决:
核心错误:NSURLComponents的初始化方式不对
Swift里的URLComponents(url:...)是结构体初始化器,但Objective-C里NSURLComponents是类,必须用Objective-C的类方法或实例初始化语法,不能直接用Swift风格的函数调用。你写的URLComponents(...)会被编译器当成未声明的C函数,所以触发了那个错误。正确写法是用类方法[NSURLComponents componentsWithURL:resolvingAgainstBaseURL:]或者实例初始化[[NSURLComponents alloc] initWithURL:resolvingAgainstBaseURL:]。printf使用错误
printf是C语言函数,不能直接传入NSURL或NSString对象,需要把它们转成C字符串,用UTF8String属性获取C语言版本的字符串。另外最好加个\n换行,不然打印会连在一起。空合运算符的差异
Objective-C里没有Swift的??空合运算符,要处理urlComponents.host可能为空的情况,用Objective-C的三目运算符?:,写成urlComponents.host ?: @"",意思是如果host不为空就用它,否则用空字符串。语法细节问题
NSString * const host = ...这一行末尾少了分号,Objective-C语句必须以分号结尾;- Objective-C里返回布尔值规范写法是用
YES而不是true(虽然true在iOS里也能识别,但YES是Objective-C的标准布尔常量)。
修正后的完整Objective-C代码:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options { // 打印URL的字符串形式,转成C字符串给printf printf("%s\n", [url absoluteString].UTF8String); // 用Objective-C类方法初始化NSURLComponents NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:YES]; // 三目运算符处理空host NSString *host = urlComponents.host ?: @""; // 打印host字符串 printf("%s\n", host.UTF8String); return YES; }
内容的提问来源于stack exchange,提问作者Oleg

