1、UIProgressView高度问题
在xcode12环境下的iOS14系统,UIProgressView的默认高度有8像素左右,需要做相应的适配
/* Xcode12-IOS14的兼容 */
if (@available(iOS 14.0, *)) {
CGAffineTransform transform = CGAffineTransformMakeScale(1.0f, 1.0f);
transform = CGAffineTransformMakeScale(1.0f, 0.5f);
_progressView.transform = transform;
}
2、iOS14.0-14.1导航栏堆栈推出导致Tabbar隐藏
iOS14.0与IOS14.1导航栏堆栈推出后,Tabbar会被隐藏,iOS14.2没有发现该问题
- (NSArray<UIViewController *> *)popToRootViewControllerAnimated:(BOOL)animated {
if (@available(iOS 14.0, *)) {
if (self.viewControllers.count > 1) {
self.topViewController.hidesBottomBarWhenPushed = NO;
}
};
return [super popToRootViewControllerAnimated:animated];
}
- (NSArray<UIViewController *> *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated {
if (@available(iOS 14.0, *)) {
if (self.viewControllers.count > 1) {
self.topViewController.hidesBottomBarWhenPushed = NO;
}
};
return [super popToViewController:viewController animated:animated];
}
3、UITabViewCell添加subView的方式
iOS14推荐使用[UITabViewCell.contentView addSubview:],不推荐使用[UITabViewCell addSubview:]
4、获取IDFA的差异
在xcode12环境下的iOS14系统,获取到IDFA信息需要配置NSUserTrackingUsageDescription,且用户授权。
配置如下:
<!-- info.plist -->
<key>NSUserTrackingUsageDescription</key>
<string>需要使用您的广告追踪权限来追踪广告</string>
/* xcode12&iOS14兼容 */
if (@available(iOS 14.0, *)) {
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
if (status == ATTrackingManagerAuthorizationStatusAuthorized) {
NSString * strAdid = [[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
}];
}
5、WXImageView、FLAnimatedImage、YYAnimatedImage图片加载不出来
在iOS 14之前,UIKit在调用displayLayer:
之前就会去渲染UIImageView.image;
而在iOS 14,UIKit则是先去调用displayLayer:
,如果你实现了displayLayer:
,那么UIKit就不会再去渲染了。
@implementation WXImageView
...
- (void)setImage:(UIImage *)image {
[super setImage:image];
if (image) {
self.layer.contents = (id)image.CGImage;
} else {
self.layer.contents = nil;
}
}
@end
@implementation FLAnimatedImageView
...
- (void)displayLayer:(CALayer *)layer {
if (_currentFrame) {
layer.contentsScale = _currentFrame.scale;
layer.contents = (__bridge id)_currentFrame.CGImage;
} else {
// If we have no animation frames, call super implementation. iOS 14+ UIImageView use this delegate method for rendering.
if ([UIImageView instancesRespondToSelector:@selector(displayLayer:)]) {
[super displayLayer:layer];
}
}
}
@end
@implementation YYAnimatedImageView
...
- (void)displayLayer:(CALayer *)layer {
if (_curFrame) {
layer.contentsScale = _curFrame.scale;
layer.contents = (__bridge id)_curFrame.CGImage;
} else {
// If we have no animation frames, call super implementation. iOS 14+ UIImageView use this delegate method for rendering.
if ([UIImageView instancesRespondToSelector:@selector(displayLayer:)]) {
[super displayLayer:layer];
}
}
}
@end
上面的方式是直接到第三库源码修改,也可以通过hook的方式实现,不用去改动第三库的源码。
@implementation WXImageViewHook
+ (void)load {
/* Xcode12-IOS14的兼容 */
if (@available(iOS 14.0, *)) {
[self startHook];
}
}
+ (void)startHook {
Class cls = NSClassFromString(@"WXImageView");
SEL selector = NSSelectorFromString(@"setImage:");
typedef void (^WXImageViewSetImageBlock)(UIImageView* t_self, UIImage* image);
WXImageViewSetImageBlock implementationBlock = ^(UIImageView* t_self, UIImage* image) {
struct objc_super t_super = {
.receiver = t_self,
.super_class = class_getSuperclass([t_self class])
};
void(*msgSendSuper)(struct objc_super*, SEL, UIImage*) = (void*)&objc_msgSendSuper;
msgSendSuper(&t_super, NSSelectorFromString(@"setImage:"), image);
if (image) {
t_self.layer.contents = (id)image.CGImage;
} else {
t_self.layer.contents = nil;
}
};
[MKHookUtil addImplementationOfSelector:selector forClass:cls implementationBlock:implementationBlock];
}
@end
@implementation FLAnimatedImageView (Hook)
+ (void)load {
/* Xcode12-IOS14的兼容 */
if (@available(iOS 14.0, *)) {
[MKHookUtil swizzMethodOriginalSelector:@selector(displayLayer:) swizzledSelector:@selector(swizzing_displayLayer:) forClass:[self class]];
}
}
- (void)swizzing_displayLayer:(CALayer *)layer {
Ivar ivar = class_getInstanceVariable(self.class, "_currentFrame");
UIImage *_currentFrame = object_getIvar(self, ivar);
if (_currentFrame) {
layer.contentsScale = _currentFrame.scale;
layer.contents = (__bridge id)_currentFrame.CGImage;
} else {
// If we have no animation frames, call super implementation. iOS 14+ UIImageView use this delegate method for rendering.
if ([UIImageView instancesRespondToSelector:@selector(displayLayer:)]) {
[super displayLayer:layer];
}
}
}
@end
@implementation YYAnimatedImageView (Hook)
+ (void)load {
if (@available(iOS 14.0, *)) {
[MKHookUtil swizzMethodOriginalSelector:@selector(displayLayer:) swizzledSelector:@selector(swizzing_displayLayer:) forClass:[self class]];
}
}
- (void)swizzing_displayLayer:(CALayer *)layer {
Ivar ivar = class_getInstanceVariable(self.class, "_curFrame");
UIImage *_curFrame = object_getIvar(self, ivar);
if (_curFrame) {
layer.contentsScale = _curFrame.scale;
layer.contents = (__bridge id)_curFrame.CGImage;
} else {
// If we have no animation frames, call super implementation. iOS 14+ UIImageView use this delegate method for rendering.
if ([UIImageView instancesRespondToSelector:@selector(displayLayer:)]) {
[super displayLayer:layer];
}
}
}
@end