测试环境: Xcode 10.1 Swift 4.2
如果在 OC 和 Swift 混编的项目中使用了 SDWebImage,那么在 Swift 文件中 imageView 设置网络图片时没有像 OC 中那么自然和顺利,先看 OC:
// OC
[imageView sd_setImageWithURL:someURL placeholderImage:somePlaceholder];
自动完成很自然顺畅:

然而,Swift 就没有那么好可以自动完成了,同样的尝试:

通过查找方法的源头,从 SDWebImage 的 UIImageView + WebCache.h 的源代码中可以看到一个关键词 NS_REFINED_FOR_SWIFT,如下:
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder NS_REFINED_FOR_SWIFT;
这个方法声明后面紧跟的是 NS_REFINED_FOR_SWIFT
系统的宏定义:
// Foundation/NSObjcRuntime.h
#define NS_REFINED_FOR_SWIFT CF_REFINED_FOR_SWIFT
单词 refine
的含义是提炼
,顾名思义是只这个函数是从其他函数中提炼而来,由此可以发现 UIImageView+WebCache 中的其他函数也有同样的定义:
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT;
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT;
进入 .m 查看它们的实现,就不难得出结论:这些方法都是由一个更多参数的 sd_setImageWithURL:placeholderImage:options:progress:completed: 提炼而来,其本质是在内部提供了这个多参数函数一些默认参数。
@implementation UIImageView (WebCache)
- (void)sd_setImageWithURL:(nullable NSURL *)url {
[self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil];
}
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder {
[self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil];
}
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options {
[self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil];
}
- (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock {
[self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock];
}
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock {
[self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:completedBlock];
}
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock {
[self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock];
}
....
@end
那么回到 Swift 的调用,由于 Swift 函数支持默认参数的特性,标记有 NS_REFINED_FOR_SWIFT
的 OC 方法到了 Swift 中就由对应的带有默参数的多参数函数来实现了。因此 Swift 实际调用时先调用多参数函数:
extension UIImageView {
func sd_setImageWithURL(_ URL?,
placeholderImage: UIImage? = nil,
options: [SDWebImageOptions] = [],
completed: SDExternalCompletionBlock? = nil)
{ ... }
}
直接调用此函数,方式一:
func test() {
let imageView = UIImageView()
let url = URL(string: "https://qq.com")
let placeholder = UIImage(named: "image")
imageView.sd_setImage(with: url,
placeholderImage: placeholder,
options: [],
completed: nil)
}
再结合默认参数特性,将不需要的默认参数直接删除即可,方式二:
func test() {
let imageView = UIImageView()
let url = URL(string: "https://qq.com")
let placeholder = UIImage(named: "image")
imageView.sd_setImage(with: url, placeholderImage: placeholder)
}
更多的混编使用的宏
NS_SWIFT_NAME
: 用来给一个 OC 函数、类型等一个 Swift 名字
#define NS_SWIFT_NAME(_name) CF_SWIFT_NAME(_name)
反之 Swift 的类型可以在 OC 调用时重命名,使用 @objc(renamed) 语法
@objc(MBPlacemark)
open class Placemark: NSObject, Codable {
....
}
加个微信,随时联系 😆

网友评论