We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
4.3.57
iOS 原生
连续调用 PAGImageView 的 - (void)setPathAsync:completionBlock: 不会产生崩溃
1 当第一次调用 PAGImageView 的 - (void)setPathAsync:completionBlock: 时,下面函数会去下载 PAG 文件:
+ (PAGFile*)Load:(NSString*)path { if (path == nil) { return nil; } if ([PAGFileImpl IsNetWorkPath:path]) { NSData* cacheData = [PAGDiskCacheImpl ReadFile:path]; if (cacheData == nil) { NSError* error = nil; cacheData = [NSData dataWithContentsOfURL:[NSURL URLWithString:path] options:NSDataReadingUncached error:&error]; // 同步网络下载 if (error == nil && cacheData != nil) { [PAGDiskCacheImpl WritFile:path data:cacheData]; } } return [PAGFileImpl Load:cacheData.bytes size:cacheData.length path:path]; } auto pagFile = pag::PAGFile::Load([path UTF8String]); if (pagFile == nullptr) { return nil; } return (PAGFile*)[PAGLayerImpl ToPAGLayer:pagFile]; }
2 如果此时同一个 PAGImageView 对象触再次触发 - (void)setPathAsync:completionBlock: 调用,下面函数会将 PAGImageView 持有的文件 path 释放掉:
- (void)setPathAsync:(NSString*)path maxFrameRate:(float)maxFrameRate completionBlock:(void (^)(PAGFile*))callback { if (filePath != nil) { [filePath release]; // 释放之前的 filePath filePath = nil; } filePath = [path retain]; [PAGFile LoadAsync:path completionBlock:^(PAGFile* pagFile) { [self setComposition:pagFile maxFrameRate:maxFrameRate]; callback(pagFile); }]; }
这样造成的结果是,第一步的网络下载成功之后,调用后面的 [PAGDiskCacheImpl WritFile:path data:cacheData]; 方法访问了 path 变量,此时这个 path 变量已经被 release 了,会崩在这个方法的内部:
+ (BOOL)WritFile:(NSString*)key data:(NSData*)data { if (key == nil || data == nil) { return false; } std::string cacheKey = [key UTF8String]; // 会崩在 UTF8String 这里 auto cacheDatas = tgfx::Data::MakeWithoutCopy(data.bytes, data.length); return pag::DiskCache::WriteFile(cacheKey, cacheDatas); }
原因是下载是在一个 C++ block 里面执行的:
+ (void)LoadAsync:(NSString*)path completionBlock:(void (^)(PAGFile*))callback { if (path == nil) { callback(nil); return; } void (^copyCallback)(PAGFile*) = Block_copy(callback); tgfx::Task::Run([callBack = copyCallback, path]() { // 在这个 Block 里面执行下载 PAGFile* file = [PAGFileImpl Load:path]; // 下载函数 callBack(file); Block_release(callBack); }); }
但是 C++ block 捕获 path 变量并不会增加 OC 对象的引用计数,导致前面第 2 次调用 - (void)setPathAsync:completionBlock: 释放了 path,访问了野指针崩溃
同时,如果直接调用 PAGFile 的 LoadAsync:completionBlock:方法,这个问题也容易出现,原因和上面是一样的。
Demo 运行复现 内存访问错误demo.zip
The text was updated successfully, but these errors were encountered:
有解决办法了吗?我也遇到同样的问题了
Sorry, something went wrong.
kevingpqi123
No branches or pull requests
【版本信息】
4.3.57
【平台信息】
iOS 原生
【预期的表现】
连续调用 PAGImageView 的 - (void)setPathAsync:completionBlock: 不会产生崩溃
【实际的情况】
1 当第一次调用 PAGImageView 的 - (void)setPathAsync:completionBlock: 时,下面函数会去下载 PAG 文件:
2 如果此时同一个 PAGImageView 对象触再次触发 - (void)setPathAsync:completionBlock: 调用,下面函数会将 PAGImageView 持有的文件 path 释放掉:
这样造成的结果是,第一步的网络下载成功之后,调用后面的 [PAGDiskCacheImpl WritFile:path data:cacheData]; 方法访问了 path 变量,此时这个 path 变量已经被 release 了,会崩在这个方法的内部:
原因是下载是在一个 C++ block 里面执行的:
但是 C++ block 捕获 path 变量并不会增加 OC 对象的引用计数,导致前面第 2 次调用 - (void)setPathAsync:completionBlock: 释放了 path,访问了野指针崩溃
同时,如果直接调用 PAGFile 的 LoadAsync:completionBlock:方法,这个问题也容易出现,原因和上面是一样的。
【Demo及附件】
Demo 运行复现
内存访问错误demo.zip
The text was updated successfully, but these errors were encountered: