问题描述:在加载多张高清大图时,会出现崩溃的现象
解决方案:将宽度大于320的图片,裁剪宽度为320,高度等比例的图
//代码调用方式
[imgView setImageWithURL:[NSURL URLWithString:imageUrl]
placeholder:DefaultIcon
options:kNilOptions
manager:[MGCircleHelper bigImageManager]
progress:nil
transform:nil
completion:nil];
//MGCircleHelper.m
static const CGFloat MGCircleHelperTransformWidthValue = 320;
@implementation MGCircleHelper
+ (YYWebImageManager *)bigImageManager {
static YYWebImageManager *manager;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *path = [[UIApplication sharedApplication].cachesPath stringByAppendingPathComponent:@"migu.bigImage"];
YYImageCache *cache = [[YYImageCache alloc] initWithPath:path];
manager = [[YYWebImageManager alloc] initWithCache:cache queue:[YYWebImageManager sharedManager].queue];
manager.sharedTransformBlock = ^(UIImage *image, NSURL *url) {
if (!image || image.size.width <= MGCircleHelperTransformWidthValue) {
return image;
}
CGFloat aspectRatio = image.size.width / image.size.height;
CGFloat resultHeight = MGCircleHelperTransformWidthValue / aspectRatio;
return [image imageByResizeToSize:CGSizeMake(MGCircleHelperTransformWidthValue, resultHeight)];
};
});
return manager;
}
@end
问题描述:排查内存泄漏时,发现网上通用的截屏实现方式,会出现内存泄漏
解决方案:修改截屏的实现方式
- (UIImage *)screenshot {
UIWindow *window = [UIApplication sharedApplication].keyWindow;
UIGraphicsBeginImageContextWithOptions(window.bounds.size, YES, [UIScreen mainScreen].scale);
[window.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
改为
- (UIImage *)screenshot {
UIWindow *window = [UIApplication sharedApplication].keyWindow;
UIGraphicsBeginImageContextWithOptions(window.bounds.size, YES, [UIScreen mainScreen].scale);
[window drawViewHierarchyInRect:window.bounds afterScreenUpdates:YES];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
技术前言
项目中引入开源的第三方库barragerenderer和OCBarrage,在直播间,会出现卡顿的情况,打字发表弹幕时,在文字弹出键盘的瞬间,会出现卡顿现象
发生的问题
引入“OCBarrage"库后发现,业务要求弹幕先在第一条轨道出现,显示不下再在第二天轨道显示,以此类推。此库未提供现成的接口实现此功能,亦未实现防止碰撞的功能,阅读源码发现,在OCBarrageDescriptor类中,有提供一个bindingoriginy属性,来改变弹幕视图,于是来尝试自己实现防碰撞功能(下次在找第三库的时候,一定要看清楚源码,是否和自己需求的功能一样)
防碰撞功能实现
//MGCustomLiveBarrageManager.h
#import
@class MGCustomLivePlayerView;
@interface MGCustomLiveBarrageManager : NSObject
- (instancetype)init UNAVAILABLE_ATTRIBUTE;
+ (instancetype)new UNAVAILABLE_ATTRIBUTE;
-(instancetype)initWithPlayerContainer:(MGCustomLivePlayerView *)playerContainer;
/**
显示弹幕
*/
- (void)showBarrage;
/**
关闭弹幕
*/
- (void)closeBarrage;
@end
//MGCustomLiveBarrageManager.m
static const CGFloat kBarrageDefaultTextSize = 20;
static const CGFloat MGCustomLiveBarrageManagerTopMarge = 3;
@interface MGCustomLiveBarrageManager ()
/**
视频播放容器
*/
@property (nonatomic, weak) MGCustomLivePlayerView *playerContainer;
@property (nonatomic, strong) OCBarrageManager *barrageManager;
@end
@implementation MGCustomLiveBarrageManager
#pragma mark - life cycle
- (instancetype)initWithPlayerContainer:(MGCustomLivePlayerView *)playerContainer {
self = [super init];
if (self) {
_playerContainer = playerContainer;
_danMuTextSizeRate = [JHPlayerSetting shareInstance].danMuTextSizeRate;
_danMuSpeed = [JHPlayerSetting shareInstance].danMuSpeed;
[self addListener];
[self.playerContainer insertSubview:self.barrageManager.renderView atIndex:1];
[self.barrageManager.renderView mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.equalTo(self.playerContainer);
make.trailing.equalTo(self.playerContainer);
make.top.equalTo(self.playerContainer).offset(44-MGCustomLiveBarrageManagerTopMarge);
make.bottom.equalTo(self.playerContainer).offset(-49);
}];
}
return self;
}
#pragma mark - public method
- (void)showBarrage {
[self.barrageManager start];
}
- (void)closeBarrage {
[self.barrageManager stop];
}
#pragma mark - private method
//发送弹幕
- (OCBarrageTextDescriptor *)textDescriptorWithContent:(NSString *)content
textSize:(CGFloat)textSize
textColor:(UIColor *)textColor
isSendByMe:(BOOL)isSendByMe {
if (!content.length || !textColor) {
return nil;
}
CGFloat fontSize = textSize * self.danMuTextSizeRate;
NSAttributedString *attributeString = [[NSAttributedString alloc] initWithString:content attributes:@{NSForegroundColorAttributeName:textColor,NSFontAttributeName:[UIFont systemFontOfSize:fontSize],NSVerticalGlyphFormAttributeName:@0}];
OCBarrageTextDescriptor *bannerDescriptor = [[OCBarrageTextDescriptor alloc] init];
bannerDescriptor.text = content;
bannerDescriptor.textColor = textColor;
bannerDescriptor.attributedText = attributeString;
bannerDescriptor.textFont = [UIFont systemFontOfSize:fontSize];
bannerDescriptor.positionPriority = isSendByMe?OCBarragePositionVeryHigh: OCBarragePositionMiddle;
bannerDescriptor.animationDuration = self.danMuSpeed;
bannerDescriptor.barrageCellClass = [MGBarrageTextCell class];
//设置originY的值
bannerDescriptor.bindingOriginY = [self bindingOriginY:5];
if (isSendByMe) {
bannerDescriptor.borderColor = textColor;
bannerDescriptor.borderWidth = 1;
}
return bannerDescriptor;
}
/**
* 根据轨道数,获取弹幕的Y轴的值
*/
- (CGFloat)bindingOriginY:(NSUInteger)totalTrackNumber {
if (totalTrackNumber == 0) {
return 0;
}
UIFont *font = [UIFont systemFontOfSize:kBarrageDefaultTextSize * self.danMuTextSizeRate];
CGFloat lineHeight = font.lineHeight+MGCustomLiveBarrageManagerTopMarge;
NSMutableArray *trackKeys = [NSMutableArray arrayWithCapacity:totalTrackNumber];
for (NSUInteger i = 0; i < totalTrackNumber; i++) {
NSString *trackKey = [NSString stringWithFormat:@"track%lu",(unsigned long)i];
[trackKeys addObject:trackKey];
}
NSMutableDictionary *trackDictionary = [NSMutableDictionary dictionaryWithCapacity:trackKeys.count];
// 1、根据当前行高,区分正在显示的弹幕
NSMutableArray *animatingCells = [self.barrageManager.renderView.animatingCells mutableCopy];
for (NSInteger i = 0; i < trackKeys.count; i++) {
NSMutableArray *lineArray = [NSMutableArray array];
CGFloat seperateHeight = lineHeight * (i+1);
NSArray *containCells = [animatingCells copy];
for (OCBarrageCell *barrageCell in containCells) {
CGFloat maxOrginalX = CGRectGetMaxX(barrageCell.layer.presentationLayer.frame);
CGFloat minOrginalY = CGRectGetMinY(barrageCell.layer.presentationLayer.frame);
// 保存符合要求的x轴的值
if (minOrginalY < seperateHeight) {
[lineArray addObject:@(maxOrginalX)];
[animatingCells removeObject:barrageCell];
}
}
NSString *key = [trackKeys objectOrNilAtIndex:i];
[trackDictionary setValue:[lineArray copy] forKey:key];
}
// 2、根据每条轨道的数组中x轴的值,获取到需要显示的弹幕y轴的值
CGRect renderViewFrame = self.barrageManager.renderView.frame;
for (NSInteger i = 0; i < trackKeys.count; i++) {
NSString *key = [trackKeys objectOrNilAtIndex:i];
NSArray *lineArray = [trackDictionary objectForKey:key];
__block BOOL fetchResult = YES;
[lineArray enumerateObjectsUsingBlock:^(NSNumber * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj floatValue] > CGRectGetMaxX(renderViewFrame)) {
fetchResult = NO;
*stop = YES;
}
}];
if (fetchResult || (lineArray.count == 0)) {
return [self barrageOriginYWithTrackNumber:i lineHeight:lineHeight];
}
}
NSInteger random = arc4random() % totalTrackNumber;
return [self barrageOriginYWithTrackNumber:random lineHeight:lineHeight];
}
- (CGFloat)barrageOriginYWithTrackNumber:(NSInteger)trackNumber
lineHeight:(CGFloat)lineHeight{
CGFloat barrageOriginY = trackNumber * lineHeight + MGCustomLiveBarrageManagerTopMarge;
CGFloat maxY = CGRectGetHeight(self.barrageManager.renderView.frame);
//如果y轴的值,超出了视图范围,提供一个随机值。
if ((barrageOriginY + lineHeight) > maxY) {
barrageOriginY = (arc4random()%trackNumber)* lineHeight + MGCustomLiveBarrageManagerTopMarge;;
}
return barrageOriginY;
}
@end