self.nameVarPtr = [[ObjectName alloc] init] 和nameVarPtr = [[ObjectName alloc] init] 的区别

本文详细解释了Objective-C中@synthesize指令的作用,特别是当与不同变量名配合使用时如何正确生成属性的存取方法。同时对比了通过self调用setter方法与直接修改变量指针两种赋值方式的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们在进行iOS开发时,经常会在类的声明部分看见类似于@synthesize window=_window; 的语句,那么,这个window是什么,_ window又是什么,两个东西分别怎么用,这是一个比较基本的问题,也关乎我们理解Objective-C中对类、类的属性、类的存取器、类的局部变量的统一理解。
在32位系统中,如果类的 @interface 部分没有进行 ivar 声明,但有 @property 声明,在类的 @implementation 部分有响应的 @synthesize,则会得到类似下面的编译错误:
Synthesized property 'xX' must either be named the same as a compatible ivar or must explicitly name an ivar
在 64-bit时,运行时系统会自动给类添加 ivar,添加的 ivar 以一个下划线"_"做前缀。
上面声明部分的 @synthesize window=_window; 意思是说,window 属性为 _window 实例变量合成访问器方法。
也就是说,window属性生成存取方法是setWindow,这个setWindow方法就是_window变量的存取方法,它操作的就是_window这个变量。通过这个看似是赋值的这样一个操作,我们可以在@synthesize 中定义与变量名不相同的getter和setter的命名,籍此来保护变量不会被不恰当的访问。

下面是一个常见的例子
写法一:
C代码   收藏代码
  1. @interface MyClass:NSObject{    
  2.         MyObjecct *_myObject;  
  3. }  
  4. @property(nonamtic, retain) MyObjecct *myObject;  
  5. @end  
  6.   
  7. @implementatin MyClass  
  8. @synthesize myObject=_myObject;  
 

写法二:
C代码   收藏代码
  1. @interface MyClass:NSObject{  
  2.         
  3. }  
  4. @property(nonamtic, retain) MyObjecct *myObject;  
  5. @end  
  6.   
  7. @implementatin MyClass  
  8. @synthesize myObject=_myObject;  
 
这个类中声明了一个变量_myObject,又声明了一个属性叫myObject,然后用@synthesize生成了属性myObject的存取方法,这个存取方法的名字应该是:setmyObject和getmyObject。@synthesize myObject=_myObject的含义就是属性myObject的存取方法是做用于_myObject这个变量的。这种用法在Apple的Sample Code中很常见。
弄明白了这个语句的意思之后,我们也就清楚了myObject和_myObject的区别,那么,在使用的时候,有什么需要注意的地方,大家应该也都清楚了。是的,myObject是属性,而_ myObject才是变量,我们最终操作的变量都是myObject。
那么,同样是存取操作,语句
C代码   收藏代码
  1. self.nameVarPtr = [[ObjectName alloc] init]   
 
C代码   收藏代码
  1. nameVarPtr = [[ObjectName alloc] init]  
两种赋值方式的区别何在呢?

 

self.nameVarPtr=xxx 这种赋值方式等价于调用 [self setnameVarPtr:xxx], 而setnameVarPtr:xxx的方法的实现又是依赖于@property的属性的,比如retain,assign等属性。


nameVarPtr = xxx 的赋值方式,仅仅是对一个指针进行赋值。nameVarPtr仅仅是一个指针变量,记录了xxx的地址。在这个过程中不会调用setter方法,不会调用setter方法,就和@property没有关系,从而,也和retain,assign等属性没有关系。这种赋值方式就是一个简单的指针赋值。


综上,对成员变量进行赋值,为防内存泄露需要注意的点:

1.self调用setter方法的方式

ObjectName*  tmp= [[ObjectName alloc] init];

self.nameVarPtr =tmp;                 //retainCount=2

[tmp release];                               //retainCount=1


2.指针赋值方式,不会调用setter方法

nameVarPtr= [[ObjectName alloc] init]; // retainCount=1


所以,笔者建议大家在对某个变量进行赋值操作的时候,尽量要写self.myObj = xxx; 这才是最可靠的方法。

class YoLov5TRT(object): """ description: A YOLOv5 class that warps TensorRT ops, preprocess and postprocess ops. """ def __init__(self, engine_file_path): # Create a Context on this device, self.ctx = cuda.Device(0).make_context() stream = cuda.Stream() TRT_LOGGER = trt.Logger(trt.Logger.INFO) runtime = trt.Runtime(TRT_LOGGER) # Deserialize the engine from file with open(engine_file_path, "rb") as f: engine = runtime.deserialize_cuda_engine(f.read()) context = engine.create_execution_context() host_inputs = [] cuda_inputs = [] host_outputs = [] cuda_outputs = [] bindings = [] for binding in engine: print('bingding:', binding, engine.get_binding_shape(binding)) size = trt.volume(engine.get_binding_shape( binding)) * engine.max_batch_size dtype = trt.nptype(engine.get_binding_dtype(binding)) # Allocate host and device buffers host_mem = cuda.pagelocked_empty(size, dtype) cuda_mem = cuda.mem_alloc(host_mem.nbytes) # Append the device buffer to device bindings. bindings.append(int(cuda_mem)) # Append to the appropriate list. if engine.binding_is_input(binding): self.input_w = engine.get_binding_shape(binding)[-1] self.input_h = engine.get_binding_shape(binding)[-2] host_inputs.append(host_mem) cuda_inputs.append(cuda_mem) else: host_outputs.append(host_mem) cuda_outputs.append(cuda_mem) # Store self.stream = stream self.context = context self.engine = engine self.host_inputs = host_inputs self.cuda_inputs = cuda_inputs self.host_outputs = host_outputs self.cuda_outputs = cuda_outputs self.bindings = bindings self.batch_size = engine.max_batch_size
07-07
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; // 保存当前播放状态进度 NSIndexPath * indexPath = [self metalienKK_getCurrentIndexPath]; MetalienKKDynamicModel * currentModel = self.dataSource[indexPath.row]; CGFloat playTime = currentModel.currentPlaybackTime; BOOL wasPlaying = currentModel.isPlaying; BOOL willBeFullScreen = (size.width > size.height); currentModel.isFullScreen = willBeFullScreen; // 更新控件可见性 self.metalienKK_statusImageView.hidden = willBeFullScreen; self.backButton.hidden = willBeFullScreen; self.searchButton.hidden = willBeFullScreen; self.shareButton.hidden = willBeFullScreen; self.portraitButton.hidden = !willBeFullScreen; // 暂停当前播放但不重置 MetalienKKShortVideoItemCollectionViewCell * currentCell = [self.collectionView cellForItemAtIndexPath:indexPath]; [currentCell.metalienKK_playerView metalienKK_pauseShortVideoWithoutReset]; // 更新约束 [self metalienKK_updateContainerFrameForSize:size isFullScreen:willBeFullScreen atIndexPath:indexPath]; // 更新布局而不重载数据 [coordinator animateAlongsideTransition:^(id <UIViewControllerTransitionCoordinatorContext> context) { // 立即刷新布局避免闪烁 [UIView performWithoutAnimation:^{ [self.collectionView.collectionViewLayout invalidateLayout]; [self.collectionView layoutIfNeeded]; [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:NO]; }]; // 更新旋转状态 [currentCell.metalienKK_playerView metalienKK_shortVideoPlayerViewRotate:willBeFullScreen]; } completion:^(id <UIViewControllerTransitionCoordinatorContext> context) { self.collectionView.scrollEnabled = !currentModel.isFullScreen; // 恢复播放状态 if (wasPlaying) { [currentCell.metalienKK_playerView metalienKK_startPlayShortVideo]; [currentCell.metalienKK_playerView metalienKK_seekToTime:playTime]; } else { [currentCell.metalienKK_playerView metalienKK_pauseShortVideo]; } // 执行等待中的动作 if (self.interfaceOrientationBlock) { self.interfaceOrientationBlock(); self.interfaceOrientationBlock = nil; } }]; } #import "MetalienKKShortVideoPlayerView.h" #define MetalienKK_kMiniPlayerViewHeight (265.0) #define MetalienKK_kBottomViewHeight (55.0 + MetalienKK_SafeAreaBottom) #define MetalienKK_kProgressViewSize CGSizeMake(MetalienKK_ScreenWidth - 15*2.0, 18.0) #define MetalienKK_kFullScreenDefaultSize CGSizeMake(110, 30) #define MetalienKK_FullScreenOpenButtonFont MetalienKK_RegularFont(12) @implementation MetalienKKShortVideoPlayerView /// 加载子视图 - (void)metalienKK_loadSubviews { // 新增视图 [self addSubview:self.metalienKK_playerView]; [self addSubview:self.metalienKK_maskView]; [self addSubview:self.metalienKK_bottomView]; [self addSubview:self.metalienKK_durationLabel]; [self addSubview:self.metalienKK_contentView]; [self addSubview:self.metalienKK_userView]; [self addSubview:self.metalienKK_progressView]; [self addSubview:self.metalienKK_popupView]; [self addSubview:self.metalienKK_loadingView]; [self addSubview:self.metalienKK_fullScreenButton]; [self addSubview:self.metalienKK_playImageView]; [self.metalienKK_playerView addSubview:self.metalienKK_videoEngine.playerView]; [self.metalienKK_bottomView addSubview:self.metalienKK_likeButton]; [self.metalienKK_bottomView addSubview:self.metalienKK_bottomLineView_1]; [self.metalienKK_bottomView addSubview:self.metalienKK_bottomLineView_2]; [self.metalienKK_bottomView addSubview:self.metalienKK_commentButton]; [self.metalienKK_bottomView addSubview:self.metalienKK_wowButton]; // 设置约束 [self.metalienKK_bottomView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.bottom.right.equalTo(self); make.height.mas_offset(MetalienKK_kBottomViewHeight); }]; [self.metalienKK_likeButton mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self.metalienKK_bottomView); make.top.equalTo(self.metalienKK_bottomView); make.width.equalTo(self.metalienKK_bottomView.mas_width).multipliedBy(1/3.0); make.height.mas_offset(55.0); }]; [self.metalienKK_bottomLineView_1 mas_makeConstraints:^(MASConstraintMaker *make) { make.centerY.equalTo(self.metalienKK_likeButton); make.right.equalTo(self.metalienKK_likeButton.mas_left); make.size.mas_offset(CGSizeMake(1, 20)); }]; [self.metalienKK_bottomLineView_2 mas_makeConstraints:^(MASConstraintMaker *make) { make.centerY.equalTo(self.metalienKK_likeButton); make.left.equalTo(self.metalienKK_likeButton.mas_right); make.size.mas_equalTo(self.metalienKK_bottomLineView_1); }]; [self.metalienKK_commentButton mas_makeConstraints:^(MASConstraintMaker *make) { make.top.left.equalTo(self.metalienKK_bottomView); make.right.equalTo(self.metalienKK_bottomLineView_1.mas_left); make.height.mas_equalTo(self.metalienKK_likeButton); }]; [self.metalienKK_wowButton mas_makeConstraints:^(MASConstraintMaker *make) { make.top.right.equalTo(self.metalienKK_bottomView); make.left.equalTo(self.metalienKK_bottomLineView_2.mas_right); make.height.mas_equalTo(self.metalienKK_likeButton); }]; [self.metalienKK_playerView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.left.right.equalTo(self); make.bottom.equalTo(self).offset(-MetalienKK_kBottomViewHeight); }]; [self.metalienKK_videoEngine.playerView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.metalienKK_playerView); }]; [self.metalienKK_popupView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self.mas_bottom); // 初始位置在底部之外 make.left.right.equalTo(self); make.height.mas_equalTo(MetalienKK_ScreenHeight - MetalienKK_StatusBarHeight - MetalienKK_kMiniPlayerViewHeight); }]; [self.metalienKK_maskView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.metalienKK_playerView); }]; [self.metalienKK_playImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.center.equalTo(self.metalienKK_playerView); make.size.mas_offset(CGSizeMake(40, 40)); }]; [self.metalienKK_progressView mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self); make.bottom.equalTo(self.metalienKK_bottomView.mas_top); make.size.mas_offset(MetalienKK_kProgressViewSize); }]; [self.metalienKK_durationLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.leading.equalTo(self.metalienKK_progressView); make.bottom.equalTo(self.metalienKK_progressView.mas_top); }]; [self.metalienKK_contentView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self); make.bottom.equalTo(self.metalienKK_progressView.mas_top); make.height.mas_offset(20.0); }]; [self.metalienKK_userView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self); make.bottom.equalTo(self.metalienKK_contentView.mas_top).offset(-12); make.height.mas_offset(36.0); }]; [self.metalienKK_fullScreenButton mas_makeConstraints:^(MASConstraintMaker *make) { make.center.equalTo(self.metalienKK_playerView); make.size.mas_equalTo(MetalienKK_kFullScreenDefaultSize); }]; [self.metalienKK_loadingView mas_makeConstraints:^(MASConstraintMaker *make) { make.center.equalTo(self.metalienKK_playerView); make.left.right.equalTo(self).inset(15.0); make.height.mas_equalTo(60); }]; // 按钮布局 [self.metalienKK_commentButton metalienKK_layoutWithStyle:MetalienKKButtonEdgeInsetsStyleImageLeft andSpace:4.0]; [self.metalienKK_likeButton metalienKK_layoutWithStyle:MetalienKKButtonEdgeInsetsStyleImageLeft andSpace:4.0]; [self.metalienKK_wowButton metalienKK_layoutWithStyle:MetalienKKButtonEdgeInsetsStyleImageLeft andSpace:4.0]; // 创建通知 [self metalienKK_setupNotifications]; } /// 创建通知 - (void)metalienKK_setupNotifications { // 应用进入后台时暂停 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillResignActiveNotification) name:UIApplicationWillResignActiveNotification object:nil]; // 应用返回前台时恢复 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidBecomeActiveNotification) name:UIApplicationDidBecomeActiveNotification object:nil]; } /// 显示&隐藏控件 - (void)metalienKK_showAndHiddenControls { self.metalienKK_fullScreenButton.hidden = self.responseData.isFullScreen ?:(!self.responseData.isHorizontalResolution); self.metalienKK_bottomView.hidden = self.responseData.isFullScreen; self.metalienKK_contentView.hidden = self.responseData.isFullScreen ?:!((self.responseData.isShowTitle || self.responseData.isShowContent)); self.metalienKK_durationLabel.hidden = self.responseData.isFullScreen ? self.responseData.isPlaying:YES; self.metalienKK_userView.hidden = self.responseData.isFullScreen ? self.responseData.isPlaying:NO; self.metalienKK_progressView.hidden = self.responseData.isFullScreen ? self.responseData.isPlaying:NO; } /// 重置约束 - (void)metalienKK_remarkConstraints { // 视频播放器 [self.metalienKK_playerView mas_remakeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self); make.left.right.equalTo(self).inset(self.responseData.isFullScreen ? 76.0:0.0); make.bottom.equalTo(self).offset(self.responseData.isFullScreen ? 0.0:(-MetalienKK_kBottomViewHeight)); }]; [self.metalienKK_videoEngine.playerView mas_remakeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.metalienKK_playerView); }]; // 用户信息视图 [self.metalienKK_userView mas_remakeConstraints:^(MASConstraintMaker *make) { if (self.responseData.isFullScreen) { make.top.equalTo(self).offset(20); make.left.right.equalTo(self).inset(94); } else { make.left.right.equalTo(self); if (!self.metalienKK_contentView.hidden) { make.bottom.equalTo(self.metalienKK_contentView.mas_top).offset(-12); } else { make.bottom.equalTo(self.metalienKK_progressView.mas_top); } } make.height.mas_offset(36.0); }]; // 进度条 [self.metalienKK_progressView mas_remakeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self); if (self.responseData.isFullScreen) { make.left.right.equalTo(self).inset(50); make.bottom.equalTo(self).offset(-39); make.height.mas_equalTo(MetalienKK_kProgressViewSize.height); } else { make.bottom.equalTo(self.metalienKK_bottomView.mas_top); make.size.mas_offset(MetalienKK_kProgressViewSize); } }]; // 内容 if (!self.metalienKK_contentView.hidden) { [self.metalienKK_contentView mas_remakeConstraints:^(MASConstraintMaker *make) { CGFloat contentHeight = [self.metalienKK_contentView metalienKK_getContentViewHeight]; make.left.right.equalTo(self); make.bottom.equalTo(self.metalienKK_progressView.mas_top); make.height.mas_offset(contentHeight); }]; } // 全屏播放按钮 if (!self.metalienKK_fullScreenButton.hidden) { [self.metalienKK_fullScreenButton mas_remakeConstraints:^(MASConstraintMaker *make) { CGSize tempSize = [self.metalienKK_fullScreenButton.currentTitle metalienKK_calculateMultipleLinesTextSizeWithFont:MetalienKK_FullScreenOpenButtonFont andMaxSize:CGSizeMake(CGFLOAT_MAX, MetalienKK_kFullScreenDefaultSize.height)]; CGFloat tempWidth = 2*12.0 + 20.0 + 8.0 + tempSize.width; if (tempWidth < MetalienKK_kFullScreenDefaultSize.width) { tempWidth = MetalienKK_kFullScreenDefaultSize.width; } CGFloat tempVideoHeight = (self.responseData.videoHeight/(self.responseData.videoWidth*1.0)) * MetalienKK_ScreenWidth; make.centerX.equalTo(self.metalienKK_playerView); make.centerY.equalTo(self.metalienKK_playerView).offset(tempVideoHeight/2.0 + 12.0 + MetalienKK_kFullScreenDefaultSize.height/2.0); make.size.mas_equalTo(CGSizeMake(tempWidth, MetalienKK_kFullScreenDefaultSize.height)); }]; } // 立即刷新 [self layoutIfNeeded]; } # pragma mark - Public /// 视图复用 - (void)metalienKK_shortVideoPlayerViewReuse { // 暂停播放 [self metalienKK_pauseShortVideo]; // 重置播放器 [self.metalienKK_videoEngine resetPlayerVideoProcessor]; } /// 视图旋转 - (void)metalienKK_shortVideoPlayerViewRotate:(BOOL)isFullScreen { // 标记 self.responseData.isFullScreen = isFullScreen; // 显示&隐藏控件 [self metalienKK_showAndHiddenControls]; // 重置约束 [self metalienKK_remarkConstraints]; } /// 刷新数据 - (void)metalienKK_reloadVideoPlayerViewWithData:(MetalienKKDynamicModel *)responseData { // 缓存 self.responseData = responseData; // 显示&隐藏控件 self.metalienKK_loadingView.hidden = responseData.isReadyDisplay; self.metalienKK_playImageView.hidden = YES; self.metalienKK_fullScreenButton.hidden = !responseData.isHorizontalResolution; // 刷新数据 [self.metalienKK_userView metalienKK_refreshShortVideoUser:responseData]; [self.metalienKK_popupView metalienKK_reloadShortVideoViewData:responseData]; // 判断是否显示文本 BOOL isShowContent = (responseData.isShowTitle || responseData.isShowContent); self.metalienKK_contentView.hidden = !isShowContent; if (isShowContent) { [self.metalienKK_contentView metalienKK_refreshShortVideoContent:responseData]; } // 视频进度 [self.metalienKK_progressView metalienKK_shortVideoSetProgress:responseData.currentPlaybackProgress]; // 设置视频资源 [self metalienKK_setupVideoEngineSource]; // 显示&隐藏控件 [self metalienKK_showAndHiddenControls]; // 重置约束 [self metalienKK_remarkConstraints]; } /// 设置视频资源 - (void)metalienKK_setupVideoEngineSource { if (self.responseData.metalienKK_mediaID.length > 0 && self.responseData.metalienKK_mediaToken.length > 0) { // 设置视频资源(使用 Video ID) [self metalienKK_setShortVideoSourceWithVideoID:self.responseData.metalienKK_mediaID andToken:self.responseData.metalienKK_mediaToken]; } else if (self.responseData.metalienKK_href.length > 0) { // 设置视频资源(使用 HTTP URL) [self metalienKK_setShortVideoSourceWithURL:self.responseData.metalienKK_href]; } } /// 预加载方法 - (void)metalienKK_preloadVideo { // 设置视频资源 [self metalienKK_setupVideoEngineSource]; // 准备播放 [self.metalienKK_videoEngine prepareToPlay]; } /// 开始播放 - (void)metalienKK_startPlayShortVideo { // 标识 self.responseData.isPlaying = YES; // 隐藏播放按钮 self.metalienKK_playImageView.hidden = YES; // 弱引用 MetalienKK_WeakSelf(self); // 播放进度 [self.metalienKK_videoEngine addPeriodicTimeObserverForInterval:0.5 queue:dispatch_get_main_queue() usingBlock:^{ // 强引用 MetalienKK_StrongSelf(self); // 刷新视频播放进度 [self metalienKK_refreshShortVideoPlaybackProgress]; }]; // 指定视频播放开始时间 [self.metalienKK_videoEngine setOptionForKey:VEKKeyPlayerStartTime_CGFloat value:@(self.responseData.currentPlaybackTime)]; // 播放视频 [self.metalienKK_videoEngine play]; } /// 暂停播放 - (void)metalienKK_pauseShortVideo { // 显示播放按钮 self.metalienKK_playImageView.hidden = NO; // 手动标记 self.responseData.isPlaying = NO; // 暂停播放 [self.metalienKK_videoEngine pause:YES]; // 移除监听 [self.metalienKK_videoEngine removeTimeObserver]; } /// 重置播放器 - (void)metalienKK_resetPlayer { // 显示播放按钮 self.metalienKK_playImageView.hidden = NO; // 手动标记 self.responseData.isPlaying = NO; // // 视频进度 // [self.metalienKK_progressView metalienKK_shortVideoSetProgress:0]; // 移除监听 [self.metalienKK_videoEngine removeTimeObserver]; // 重置播放器 [self.metalienKK_videoEngine pause:YES]; // [self.metalienKK_videoEngine resetPlayerVideoProcessor]; } // 无重置的暂停 - (void)metalienKK_pauseShortVideoWithoutReset { [self.metalienKK_videoEngine pause]; self.responseData.isPlaying = NO; } // 跳转到指定时间 - (void)metalienKK_seekToTime:(CGFloat)time { MetalienKK_WeakSelf(self); [self.metalienKK_videoEngine setCurrentPlaybackTime:time complete:^(BOOL success) { if (success) { [weak_self metalienKK_refreshShortVideoPlaybackProgress]; } }]; } # pragma mark - Notification Event /// App 进入后台 - (void)appWillResignActiveNotification { if (self.responseData.isPlaying) { [self metalienKK_pauseShortVideo]; } } /// App 即将进入前台 - (void)appDidBecomeActiveNotification { if (self.responseData.isPlaying) { [self metalienKK_startPlayShortVideo]; } } # pragma mark - Event /// 设置视频资源(使用 Video ID) - (void)metalienKK_setShortVideoSourceWithVideoID:(NSString *)videoID andToken:(NSString *)token { TTVideoEngineVidSource * videoSource = [[TTVideoEngineVidSource alloc] initWithVid:videoID playAuthToken:token resolution:TTVideoEngineResolutionTypeAuto]; [self.metalienKK_videoEngine setVideoEngineVideoSource:videoSource]; } /// 设置视频资源(使用 HTTP URL) - (void)metalienKK_setShortVideoSourceWithURL:(NSString *)videoURL { NSString * cacheKey = [videoURL metalienKK_coverToMD5String]; TTVideoEngineUrlSource * urlSource = [[TTVideoEngineUrlSource alloc] initWithUrl:videoURL cacheKey:cacheKey]; [self.metalienKK_videoEngine setVideoEngineVideoSource:urlSource]; } /// 刷新视频播放进度 - (void)metalienKK_refreshShortVideoPlaybackProgress { CGFloat playTime = self.metalienKK_videoEngine.currentPlaybackTime; CGFloat duration = self.metalienKK_videoEngine.duration; CGFloat progress = (playTime/duration); [self.metalienKK_progressView metalienKK_shortVideoSetProgress:progress]; // 视频播放进度 NSString * playTimeString = [NSString metalienKK_secondConvertToFormat:playTime]; NSString * durationString = [NSString metalienKK_secondConvertToFormat:duration]; NSString * content = [NSString stringWithFormat:@"%@ / %@", playTimeString, durationString]; NSRange playTimeRange = [content rangeOfString:playTimeString]; NSMutableAttributedString * attributedString = [[NSMutableAttributedString alloc] initWithString:content]; [attributedString addAttribute:NSForegroundColorAttributeName value:MetalienKK_ColorHexAlpha(@"#A8B0B9", 0.7) range:attributedString.yy_rangeOfAll]; [attributedString addAttribute:NSForegroundColorAttributeName value:UIColor.whiteColor range:playTimeRange]; self.metalienKK_durationLabel.attributedText = attributedString; // 缓存 self.responseData.currentPlaybackProgress = progress; self.responseData.currentPlaybackTime = playTime; } /// 弹出视图 - (void)metalienKK_showPopupViewAtIndex:(int)index { // 选中处理 if (index >= 0) { [self.metalienKK_popupView metalienKK_popupViewDidSelectIndex:index]; } // 控件显示&隐藏 self.metalienKK_fullScreenButton.hidden = YES; self.metalienKK_popupView.hidden = NO; // 标记是否弹出视图 [self metalienKK_markPopupViewIsShow:YES]; // 重置约束 [self.metalienKK_playerView mas_remakeConstraints:^(MASConstraintMaker *make) { make.top.left.right.equalTo(self); make.height.mas_equalTo(MetalienKK_kMiniPlayerViewHeight); }]; [self.metalienKK_popupView mas_remakeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self.metalienKK_playerView.mas_bottom); make.left.right.equalTo(self); make.height.mas_equalTo(MetalienKK_ScreenHeight - MetalienKK_StatusBarHeight - MetalienKK_kMiniPlayerViewHeight); }]; // 创建弹簧动画器 UISpringTimingParameters * springParams = [[UISpringTimingParameters alloc] initWithDampingRatio:0.75 initialVelocity:CGVectorMake(0.5, 0.5)]; UIViewPropertyAnimator * animator = [[UIViewPropertyAnimator alloc] initWithDuration:0.4 timingParameters:springParams]; [animator addAnimations:^{ // 强制立即刷新布局 [self layoutIfNeeded]; }]; [animator addCompletion:^(UIViewAnimatingPosition finalPosition) { [self metalienKK_disableCollectionViewScroll:YES]; }]; [animator startAnimation]; } /// 关闭视图 - (void)metalienKK_closePopupView { // 标记是否弹出视图 [self metalienKK_markPopupViewIsShow:NO]; // 重置约束 [self.metalienKK_playerView mas_remakeConstraints:^(MASConstraintMaker *make) { make.top.left.right.equalTo(self); make.bottom.equalTo(self).offset(-MetalienKK_kBottomViewHeight); }]; [self.metalienKK_popupView mas_remakeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self.mas_bottom); make.left.right.equalTo(self); make.height.mas_equalTo(MetalienKK_ScreenHeight - MetalienKK_StatusBarHeight - MetalienKK_kMiniPlayerViewHeight); }]; // 使用相同的动画参数 UISpringTimingParameters * springParams = [[UISpringTimingParameters alloc] initWithDampingRatio:0.8 initialVelocity:CGVectorMake(0, 0)]; UIViewPropertyAnimator * animator = [[UIViewPropertyAnimator alloc] initWithDuration:0.35 timingParameters:springParams]; [animator addAnimations:^{ // 强制立即刷新布局 [self layoutIfNeeded]; }]; [animator addCompletion:^(UIViewAnimatingPosition finalPosition) { self.metalienKK_fullScreenButton.hidden = !self.responseData.isHorizontalResolution; self.metalienKK_popupView.hidden = YES; [self metalienKK_disableCollectionViewScroll:NO]; }]; [animator startAnimation]; } /// 标记是否弹出视图 - (void)metalienKK_markPopupViewIsShow:(BOOL)isShow { // 缓存 self.responseData.isShowingPopupView = isShow; // 弹出&收起视图 if ([self.delegate respondsToSelector:@selector(metalienKK_collectionViewCellDidShowPopupView:)]) { [self.delegate metalienKK_collectionViewCellDidShowPopupView:isShow]; } } /// 禁止滚动 - (void)metalienKK_disableCollectionViewScroll:(BOOL)isDisable { // 移除手势 [self.metalienKK_maskView removeGestureRecognizer:self.metalienKK_maskViewBlockPanGesture]; // 判断是否禁止 if (isDisable) { [self.metalienKK_maskView addGestureRecognizer:self.metalienKK_maskViewBlockPanGesture]; } } # pragma mark - Gesture /// 点击视频 - (void)metalienKK_maskViewTapGesture:(UITapGestureRecognizer *)gesture { // 判断是否正在弹出视图 if (self.responseData.isShowingPopupView) { [self metalienKK_closePopupView]; } else { if (self.metalienKK_videoEngine.playbackState == TTVideoEnginePlaybackStatePlaying) { [self metalienKK_pauseShortVideo]; } else { [self metalienKK_startPlayShortVideo]; } } } /// 点击内容视图 - (void)metalienKK_contentViewTapGesture:(UITapGestureRecognizer *)gesture { [self metalienKK_showPopupViewAtIndex:0]; } /// 视频窗口滑动手势 - (void)metalienKK_maskViewPanGesture:(UIPanGestureRecognizer *)gesture { // Nothing ... } /// 预览视图滑动手势 - (void)metalienKK_popupViewPanGesture:(UIPanGestureRecognizer *)gesture { static CGPoint originalCenter; static CGRect originalFrame; static CGFloat initialTranslationY; CGPoint translation = [gesture translationInView:self]; CGPoint velocity = [gesture velocityInView:self]; switch (gesture.state) { case UIGestureRecognizerStateBegan: // 记录初始位置 originalCenter = self.metalienKK_popupView.center; originalFrame = self.metalienKK_popupView.frame; initialTranslationY = translation.y; break; case UIGestureRecognizerStateChanged: { // 计算新的Y位置(限制在屏幕范围内) CGFloat newY = originalFrame.origin.y + translation.y; CGFloat minY = MetalienKK_kMiniPlayerViewHeight; CGFloat maxY = MetalienKK_ScreenHeight; // 限制拖拽范围(不能超过屏幕顶部/底部) newY = MIN(MAX(newY, minY), maxY); // 应用新位置 CGRect newFrame = originalFrame; newFrame.origin.y = newY; self.metalienKK_popupView.frame = newFrame; // 计算背景视图的高度变化(跟随拖拽) CGFloat backgroundHeight = MetalienKK_kMiniPlayerViewHeight + (newY - minY); [self.metalienKK_playerView mas_updateConstraints:^(MASConstraintMaker *make) { make.height.mas_equalTo(backgroundHeight); }]; [self layoutIfNeeded]; break; } case UIGestureRecognizerStateEnded: case UIGestureRecognizerStateCancelled: { CGFloat currentY = self.metalienKK_popupView.frame.origin.y; CGFloat threshold = MetalienKK_ScreenHeight * 0.5; // 阈值设为屏幕高度的50% BOOL shouldClose = NO; // 根据速度或位置决定操作 if (velocity.y > 800) { // 快速下滑则关闭 shouldClose = YES; } else if (velocity.y < -800) { // 快速上滑则展开 shouldClose = NO; } else { // 根据位置决定 shouldClose = (currentY > threshold); } if (shouldClose) { [self metalienKK_closePopupView]; } else { [self metalienKK_showPopupViewAtIndex:-999]; } break; } default: break; } } #pragma mark - Action /// 全屏播放 - (void)metalienKK_fullScreenButtonAction:(UIButton *)sender { // 确保使用主线程执行旋转 dispatch_async(dispatch_get_main_queue(), ^{ if ([self.delegate respondsToSelector:@selector(metalienKK_fullScreenOpenButtonDidClick:)]) { [self.delegate metalienKK_fullScreenOpenButtonDidClick:sender]; } }); } /// 评论 - (void)metalienKK_commentButtonAction:(UIButton *)sender { [self metalienKK_showPopupViewAtIndex:1]; } /// 赞 & 取消赞 - (void)metalienKK_likeButtonAction:(UIButton *)sender { } /// 棒 & 取消棒 - (void)metalienKK_wowButtonAction:(UIButton *)sender { } # pragma mark - TTVideoEngineDelegate /// 播放停止回调 - (void)videoEngineUserStopped:(TTVideoEngine *)videoEngine { MetalienKK_Log(@"videoEngineUserStopped:"); } /// 播放结束回调 - (void)videoEngineDidFinish:(TTVideoEngine *)videoEngine error:(nullable NSError *)error { MetalienKK_Log(@"videoEngineDidFinish:error:"); } /// 异常播放结束回调 - (void)videoEngineDidFinish:(TTVideoEngine *)videoEngine videoStatusException:(NSInteger)status { MetalienKK_Log(@"videoEngineDidFinish:videoStatusException:"); } /// 播放器实例销毁回调 - (void)videoEngineCloseAysncFinish:(TTVideoEngine *)videoEngine { MetalienKK_Log(@"videoEngineCloseAysncFinish:"); } /// 播放状态改变回调 - (void)videoEngine:(TTVideoEngine *)videoEngine playbackStateDidChanged:(TTVideoEnginePlaybackState)playbackState { MetalienKK_Log(@"videoEngine:playbackStateDidChanged:"); self.responseData.isPlaying = (playbackState == TTVideoEnginePlaybackStatePlaying); self.metalienKK_progressView.isPlaying = self.responseData.isPlaying; // 显示&隐藏控件 [self metalienKK_showAndHiddenControls]; } /// 加载状态改变回调 - (void)videoEngine:(TTVideoEngine *)videoEngine loadStateDidChanged:(TTVideoEngineLoadState)loadState { MetalienKK_Log(@"videoEngine:loadStateDidChanged:"); if (loadState == TTVideoEngineLoadStatePlayable) { self.responseData.isLoading = NO; [self.metalienKK_progressView metalienKK_shortVideoStopLoadingAnimation]; } else { self.responseData.isLoading = YES; [self.metalienKK_progressView metalienKK_shortVideoStartLoadingAnimation]; } } /// 播放器各模块准备完成、可以播放回调 - (void)videoEnginePrepared:(TTVideoEngine *)videoEngine { MetalienKK_Log(@"videoEnginePrepared:"); self.metalienKK_progressView.duration = videoEngine.duration; } /// 视频加载完成、开始播放回调 - (void)videoEngineReadyToPlay:(TTVideoEngine *)videoEngine { MetalienKK_Log(@"videoEngineReadyToPlay:"); } /// 显示视频首帧回调 - (void)videoEngineReadyToDisPlay:(TTVideoEngine *)videoEngine { MetalienKK_Log(@"videoEngineReadyToDisPlay:(width:%ld, height:%ld)", self.responseData.videoWidth, self.responseData.videoHeight); self.responseData.isReadyDisplay = YES; self.metalienKK_loadingView.hidden = YES; } # pragma mark - TTVideoEngineResolutionDelegate /// 视频分辨率发生变化回调 - (void)videoSizeDidChange:(TTVideoEngine *)videoEngine videoWidth:(NSInteger)videoWidth videoHeight:(NSInteger)videoHeight { MetalienKK_Log(@"videoSizeDidChange:videoWidth:%ld videoHeight:%ld", (long)videoWidth, (long)videoHeight); // 缓存信息 self.responseData.videoWidth = videoWidth; self.responseData.videoHeight = videoHeight; // 按钮显示状态 self.responseData.isHorizontalResolution = (self.responseData.videoWidth > self.responseData.videoHeight); self.metalienKK_fullScreenButton.hidden = !self.responseData.isHorizontalResolution; // 重置约束 [self metalienKK_remarkConstraints]; } # pragma mark - Override - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { if (self.responseData.isShowingPopupView) { CGPoint commentPoint = [self.metalienKK_popupView convertPoint:point fromView:self]; if ([self.metalienKK_popupView pointInside:commentPoint withEvent:event]) { return [self.metalienKK_popupView hitTest:commentPoint withEvent:event]; } CGPoint maskPoint = [self.metalienKK_maskView convertPoint:point fromView:self]; if ([self.metalienKK_maskView pointInside:maskPoint withEvent:event]) { return self.metalienKK_maskView; } return self; } return [super hitTest:point withEvent:event]; } //# pragma mark - Helper // ///// 判断视图是否存在 //- (BOOL)metalienKK_isVideoEnginePlayerViewExist { // return [self.metalienKK_videoEngine.playerView isDescendantOfView:self.metalienKK_playerView]; //} # pragma mark - Getter - (TTVideoEngine *)metalienKK_videoEngine { if (!_metalienKK_videoEngine) { _metalienKK_videoEngine = [[TTVideoEngine alloc] initWithOwnPlayer:YES]; _metalienKK_videoEngine.delegate = self; _metalienKK_videoEngine.resolutionDelegate = self; _metalienKK_videoEngine.looping = YES; [_metalienKK_videoEngine setOptionForKey:VEKKeyViewScaleMode_ENUM value:@(TTVideoEngineScalingModeAspectFit)]; [_metalienKK_videoEngine setOptionForKey:VEKKeyAudioChannelEffect_ENUM value:@(TTVideoEngineAudioChannelNormal)]; // 播放 DASH 视频 [_metalienKK_videoEngine setOptionForKey:VEKKeyPlayerBashEnabled_BOOL value:@(YES)]; [_metalienKK_videoEngine setOptionForKey:VEKKeyPlayerDashEnabled_BOOL value:@(YES)]; } return _metalienKK_videoEngine; } - (MetalienKKShortVideoProgressView *)metalienKK_progressView { if (!_metalienKK_progressView) { // 弱引用 MetalienKK_WeakSelf(self); // 初始化 _metalienKK_progressView = [[MetalienKKShortVideoProgressView alloc] initWithFrame:CGRectMake(0, 0, MetalienKK_kProgressViewSize.width, MetalienKK_kProgressViewSize.height)]; [_metalienKK_progressView setOnSeek:^(NSInteger time) { // 强引用 MetalienKK_StrongSelf(self); // 跳转到指定的时间位置 [self.metalienKK_videoEngine setCurrentPlaybackTime:time complete:^(BOOL success) { // Nothing ... }]; }]; [_metalienKK_progressView metalienKK_shortVideoStartLoadingAnimation]; } return _metalienKK_progressView; } - (MetalienKKShortVideoContentPreviewView *)metalienKK_contentView { if (!_metalienKK_contentView) { _metalienKK_contentView = [[MetalienKKShortVideoContentPreviewView alloc] init]; _metalienKK_contentView.userInteractionEnabled = YES; // 添加手势 UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(metalienKK_contentViewTapGesture:)]; [_metalienKK_contentView addGestureRecognizer:tap]; } return _metalienKK_contentView; } - (MetalienKKShortVideoUserView *)metalienKK_userView { if (!_metalienKK_userView) { _metalienKK_userView = [[MetalienKKShortVideoUserView alloc] init]; } return _metalienKK_userView; } - (UIView *)metalienKK_playerView { if (!_metalienKK_playerView) { _metalienKK_playerView = [[UIView alloc] init]; _metalienKK_playerView.userInteractionEnabled = YES; } return _metalienKK_playerView; } - (UIView *)metalienKK_bottomView { if (!_metalienKK_bottomView) { _metalienKK_bottomView = [[UIView alloc] init]; _metalienKK_bottomView.backgroundColor = MetalienKK_ColorHex(@"#11111D"); } return _metalienKK_bottomView; } - (UIButton *)metalienKK_commentButton { if (!_metalienKK_commentButton) { _metalienKK_commentButton = [UIButton buttonWithType:UIButtonTypeCustom]; [_metalienKK_commentButton.titleLabel setFont:MetalienKK_BoldFont(14)]; [_metalienKK_commentButton setTitle:MetalienKK_LocalizedString(@"评论") forState:UIControlStateNormal]; [_metalienKK_commentButton setTitleColor:MetalienKK_ColorHex(@"#E6EBF4") forState:UIControlStateNormal]; [_metalienKK_commentButton setImage:[UIImage imageNamed:@"metalienKKImage_shortVideo_comment"] forState:UIControlStateNormal]; [_metalienKK_commentButton addTarget:self action:@selector(metalienKK_commentButtonAction:) forControlEvents:UIControlEventTouchUpInside]; } return _metalienKK_commentButton; } - (UIButton *)metalienKK_likeButton { if (!_metalienKK_likeButton) { _metalienKK_likeButton = [UIButton buttonWithType:UIButtonTypeCustom]; [_metalienKK_likeButton.titleLabel setFont:MetalienKK_BoldFont(14)]; [_metalienKK_likeButton setTitle:MetalienKK_LocalizedString(@"赞") forState:UIControlStateNormal]; [_metalienKK_likeButton setTitleColor:MetalienKK_ColorHex(@"#E6EBF4") forState:UIControlStateNormal]; [_metalienKK_likeButton setImage:[UIImage imageNamed:@"metalienKKImage_shortVideo_like"] forState:UIControlStateNormal]; [_metalienKK_likeButton addTarget:self action:@selector(metalienKK_likeButtonAction:) forControlEvents:UIControlEventTouchUpInside]; } return _metalienKK_likeButton; } - (UIButton *)metalienKK_wowButton { if (!_metalienKK_wowButton) { _metalienKK_wowButton = [UIButton buttonWithType:UIButtonTypeCustom]; [_metalienKK_wowButton.titleLabel setFont:MetalienKK_BoldFont(14)]; [_metalienKK_wowButton setTitle:MetalienKK_LocalizedString(@"棒") forState:UIControlStateNormal]; [_metalienKK_wowButton setTitleColor:MetalienKK_ColorHex(@"#E6EBF4") forState:UIControlStateNormal]; [_metalienKK_wowButton setImage:[UIImage imageNamed:@"metalienKKImage_shortVideo_WOW"] forState:UIControlStateNormal]; [_metalienKK_wowButton addTarget:self action:@selector(metalienKK_wowButtonAction:) forControlEvents:UIControlEventTouchUpInside]; } return _metalienKK_wowButton; } - (UIView *)metalienKK_bottomLineView_1 { if (!_metalienKK_bottomLineView_1) { _metalienKK_bottomLineView_1 = [[UIView alloc] init]; _metalienKK_bottomLineView_1.backgroundColor = MetalienKK_ColorHexAlpha(@"#848C96", 0.1); } return _metalienKK_bottomLineView_1; } - (UIView *)metalienKK_bottomLineView_2 { if (!_metalienKK_bottomLineView_2) { _metalienKK_bottomLineView_2 = [[UIView alloc] init]; _metalienKK_bottomLineView_2.backgroundColor = MetalienKK_ColorHexAlpha(@"#848C96", 0.1); } return _metalienKK_bottomLineView_2; } - (UIImageView *)metalienKK_playImageView { if (!_metalienKK_playImageView) { _metalienKK_playImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"metalienKKImage_shortVideoPlay"]]; _metalienKK_playImageView.hidden = YES; } return _metalienKK_playImageView; } - (UIView *)metalienKK_maskView { if (!_metalienKK_maskView) { _metalienKK_maskView = [[UIView alloc] init]; _metalienKK_maskView.backgroundColor = UIColor.clearColor; _metalienKK_maskView.userInteractionEnabled = YES; // 添加手势 UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(metalienKK_maskViewTapGesture:)]; [_metalienKK_maskView addGestureRecognizer:tap]; } return _metalienKK_maskView; } - (UIPanGestureRecognizer *)metalienKK_maskViewBlockPanGesture { if (!_metalienKK_maskViewBlockPanGesture) { _metalienKK_maskViewBlockPanGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(metalienKK_maskViewPanGesture:)]; } return _metalienKK_maskViewBlockPanGesture; } - (UIPanGestureRecognizer *)metalienKK_popupViewPanGesture { if (!_metalienKK_popupViewPanGesture) { _metalienKK_popupViewPanGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(metalienKK_popupViewPanGesture:)]; } return _metalienKK_popupViewPanGesture; } - (MetalienKKShortVideoPopupView *)metalienKK_popupView { if (!_metalienKK_popupView) { // 初始化视图 _metalienKK_popupView = [[MetalienKKShortVideoPopupView alloc] init]; _metalienKK_popupView.backgroundColor = [UIColor whiteColor]; _metalienKK_popupView.clipsToBounds = YES; _metalienKK_popupView.layer.cornerRadius = 12.0; _metalienKK_popupView.hidden = YES; _metalienKK_popupView.parentViewPanGestureRecognizer = self.metalienKK_popupViewPanGesture; // 添加拖拽手势 [_metalienKK_popupView addGestureRecognizer:self.metalienKK_popupViewPanGesture]; // 添加按钮事件 [_metalienKK_popupView.metalienKK_commentView.metalienKK_closeButton addTarget:self action:@selector(metalienKK_closePopupView) forControlEvents:UIControlEventTouchUpInside]; } return _metalienKK_popupView; } - (UIButton *)metalienKK_fullScreenButton { if (!_metalienKK_fullScreenButton) { _metalienKK_fullScreenButton = [UIButton buttonWithType:UIButtonTypeCustom]; [_metalienKK_fullScreenButton setFrame:CGRectMake(0, 0, MetalienKK_kFullScreenDefaultSize.width, MetalienKK_kFullScreenDefaultSize.height)]; [_metalienKK_fullScreenButton.titleLabel setFont:MetalienKK_FullScreenOpenButtonFont]; [_metalienKK_fullScreenButton setTitle:MetalienKK_LocalizedString(@"全屏播放") forState:UIControlStateNormal]; [_metalienKK_fullScreenButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal]; [_metalienKK_fullScreenButton setImage:[UIImage imageNamed:@"metalienKKImage_shortVideo_fullScreen_open"] forState:UIControlStateNormal]; [_metalienKK_fullScreenButton setClipsToBounds:YES]; [_metalienKK_fullScreenButton.layer setCornerRadius:MetalienKK_kFullScreenDefaultSize.height/2.0]; [_metalienKK_fullScreenButton.layer setBorderColor:MetalienKK_ColorHexAlpha(@"#FFFFFF", 0.15).CGColor]; [_metalienKK_fullScreenButton.layer setBorderWidth:1.0]; [_metalienKK_fullScreenButton addTarget:self action:@selector(metalienKK_fullScreenButtonAction:) forControlEvents:UIControlEventTouchUpInside]; [_metalienKK_fullScreenButton metalienKK_layoutWithStyle:MetalienKKButtonEdgeInsetsStyleImageLeft andSpace:8.0]; [_metalienKK_fullScreenButton setHidden:YES]; } return _metalienKK_fullScreenButton; } - (UILabel *)metalienKK_durationLabel { if (!_metalienKK_durationLabel) { _metalienKK_durationLabel = [[UILabel alloc] init]; _metalienKK_durationLabel.font = MetalienKK_RegularFont(14); _metalienKK_durationLabel.text = @"00:00 / 00:00"; _metalienKK_durationLabel.textColor = MetalienKK_ColorHexAlpha(@"#A8B0B9", 0.7); _metalienKK_durationLabel.hidden = YES; } return _metalienKK_durationLabel; } - (UIView *)metalienKK_loadingView { if (!_metalienKK_loadingView) { _metalienKK_loadingView = [[UIView alloc] init]; _metalienKK_loadingView.hidden = YES; // 添加图标 UIImageView * iconImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"metalienKKImage_metalienIconBig"]]; iconImageView.contentMode = UIViewContentModeScaleAspectFit; [_metalienKK_loadingView addSubview:iconImageView]; [iconImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.centerX.equalTo(_metalienKK_loadingView); make.size.mas_equalTo(CGSizeMake(40, 40)); }]; // 添加说明 UILabel * tipLabel = [[UILabel alloc] init]; tipLabel.font = MetalienKK_RegularFont(12); tipLabel.text = MetalienKK_LocalizedString(@"加载中..."); tipLabel.textColor = MetalienKK_ColorHexAlpha(@"#848C96", 0.6); [_metalienKK_loadingView addSubview:tipLabel]; [tipLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(_metalienKK_loadingView); make.bottom.equalTo(_metalienKK_loadingView); }]; } return _metalienKK_loadingView; } # pragma mark - Dealloc - (void)dealloc { // 移除通知 [[NSNotificationCenter defaultCenter] removeObserver:self]; // 销毁播放器 [self.metalienKK_videoEngine stop]; [self.metalienKK_videoEngine removeTimeObserver]; [self.metalienKK_videoEngine.playerView removeFromSuperview]; [self.metalienKK_videoEngine closeAysnc]; self.metalienKK_videoEngine = nil; } /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ @end 旋转视图时,为什么播放器的视频会黑一下,再显示出来的?
最新发布
07-17
import tensorrt as trt import numpy as np import time import pycuda.driver as cuda import pycuda.autoinit # 自定义INT8校准器类 class MyCalibrator(trt.IInt8EntropyCalibrator2): def __init__(self, batch_size=1, input_shape=(1, 3, 224, 224), cache_file="calibration.cache"): trt.IInt8EntropyCalibrator2.__init__(self) self.batch_size = batch_size self.input_shape = input_shape self.cache_file = cache_file # 生成随机校准数据(实际应用中应使用真实数据集) self.data = np.random.randn(100, *input_shape).astype(np.float32) self.current_index = 0 # 分配设备内存 self.device_input = cuda.mem_alloc(self.data.nbytes * self.batch_size) def get_batch_size(self): return self.batch_size def get_batch(self, names): if self.current_index + self.batch_size > len(self.data): return None batch = self.data[self.current_index:self.current_index+self.batch_size] self.current_index += self.batch_size # 将数据复制到设备 cuda.memcpy_htod(self.device_input, batch.tobytes()) return [int(self.device_input)] def read_calibration_cache(self): # 如果存在缓存,跳校准 try: with open(self.cache_file, "rb") as f: return f.read() except FileNotFoundError: return None def write_calibration_cache(self, cache): with open(self.cache_file, "wb") as f: f.write(cache) # 创建简单网络(使用 add_pooling_nd 替代 add_pooling) def create_network(): logger = trt.Logger(trt.Logger.WARNING) builder = trt.Builder(logger) network = builder.create_network(1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)) # 定义输入 input_tensor = network.add_input("input", trt.DataType.FLOAT, (1, 3, 224, 224)) # 添加卷积层(模拟ResNet-18第一层) conv1 = network.add_convolution_nd( input=input_tensor, num_output_maps=64, kernel_shape=(7, 7), kernel=np.random.randn(64, 3, 7, 7).astype(np.float32).ravel(), bias=np.random.randn(64).astype(np.float32) ) # 设置步长填充(直接赋值属性) conv1.stride_nd = [2, 2] conv1.padding_nd = [3, 3] # 添加池化层(使用 add_pooling_nd) window_shape = trt.Dims([3, 3]) # 修改:使用 trt.Dims pool1 = network.add_pooling_nd( input=conv1.get_output(0), type=trt.PoolingType.MAX, window_size=window_shape ) pool1.stride_nd = [2, 2] # 设置池化步长 # 展平输出为二维张量(N, C*H*W) flatten = network.add_shuffle(pool1.get_output(0)) output_shape = (1, 64 * 56 * 56) # 假设输入是 (1, 64, 56, 56) flatten.reshape_dims = tuple(output_shape) # 定义权重偏置 kernel = np.random.randn(1000, 64 * 56 * 56).astype(np.float32).ravel() bias = np.random.randn(1000).astype(np.float32) # 添加常量张量作为权重偏置 w = network.add_constant((1000, 64 * 56 * 56), kernel) b = network.add_constant((1000,), bias) # 矩阵乘法:[input] @ [weights.T] + [bias] matmul = network.add_matrix_multiply(flatten.get_output(0), trt.MatrixOperation.NONE, w.get_output(0), trt.MatrixOperation.TRANSPOSE) bias_add = network.add_elementwise(matmul.get_output(0), b.get_output(0), trt.ElementWiseOperation.SUM) # 标记输出 bias_add.get_output(0).name = "output" network.mark_output(bias_add.get_output(0)) return builder, network, logger # 主测试函数 def int8_perf_test(): # 创建网络 builder, network, logger = create_network() # 配置INT8量化 config = builder.create_builder_config() config.set_flag(trt.BuilderFlag.INT8) config.set_memory_pool_limit(trt.MemoryPoolType.WORKSPACE, 1 << 30) # 1GB工作空间 # 创建校准器并设置给配置 calib = MyCalibrator(batch_size=1, input_shape=(1, 3, 224, 224), cache_file="calibration.cache") config.int8_calibrator = calib # ✅ 正确方式:直接赋值属性 # 构建引擎(新API) engine = builder.build_engine(network, config) if not engine: print("Engine构建失败!") return # 创建执行上下文 context = engine.create_execution_context() # 准备输入输出缓冲区 input_shape = (1, 3, 224, 224) output_shape = (1, 1000) host_input = np.random.randn(*input_shape).astype(np.float32) host_output = np.empty(output_shape, dtype=np.float32) # 分配设备内存 d_input = cuda.mem_alloc(host_input.nbytes) d_output = cuda.mem_alloc(host_output.nbytes) bindings = [int(d_input), int(d_output)] # 创建CUDA流 stream = cuda.Stream() # 预热 for _ in range(5): cuda.memcpy_htod_async(d_input, host_input, stream) context.execute_async_v2(bindings=bindings, stream_handle=stream.handle) cuda.memcpy_dtoh_async(host_output, d_output, stream) stream.synchronize() # 正式测试 start = time.time() for _ in range(100): cuda.memcpy_htod_async(d_input, host_input, stream) context.execute_async_v2(bindings=bindings, stream_handle=stream.handle) cuda.memcpy_dtoh_async(host_output, d_output, stream) stream.synchronize() total_time = time.time() - start # 计算INT8 TOPS(基于ResNet-18的3.9G MACs) # 注意:INT8操作数 = MACs × 2(乘加各算一次操作) ops = 3.9e9 * 2 # ResNet-18的INT8操作数 tops = (ops * 100) / (total_time * 1e12) # 100次推理 print(f"INT8 TOPS: {tops:.2f} TOPS") # 清理资源 del context del engine if __name__ == "__main__": int8_perf_test() 报错 jp@jp-Super-Server:~/test$ python3 TensorRT_int8.py /home/jp/test/TensorRT_int8.py:113: DeprecationWarning: Use Deprecated in TensorRT 10.1. Superseded by explicit quantization. instead. config.int8_calibrator = calib # ✅ 正确方式:直接赋值属性 Traceback (most recent call last): File "/home/jp/test/TensorRT_int8.py", line 166, in <module> int8_perf_test() File "/home/jp/test/TensorRT_int8.py", line 116, in int8_perf_test engine = builder.build_engine(network, config) AttributeError: 'tensorrt_bindings.tensorrt.Builder' object has no attribute 'build_engine' 给出修改后的完整代码
06-18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值