SwiftUI Scrollview Kingfisher KFImage Firebase Storage IDEDebugSessionErrorDomain 代码:4 来自调试器的消息:由于内存问题而终止

如何解决SwiftUI Scrollview Kingfisher KFImage Firebase Storage IDEDebugSessionErrorDomain 代码:4 来自调试器的消息:由于内存问题而终止

我正在使用 Swift/SwiftUI 在 XCode 12.3 中进行开发。我遇到了一个问题,在调用 Firebase 存储下载 API 时,当用户滚动时,图像内存不会从 scrollView 中释放出来。最终应用程序崩溃了 ~3GB 的内存。如果我调用我的 Flickr Image 下载,内存被释放得很好并且内存保持在大约 140MB。

我的具体问题是,我需要更改什么才能允许 firebase 调用在滚动时从内存中删除图像,类似于 Flickr 调用的工作方式?

我在调用 Firebase 的过程中收到以下错误,但图像是从传递给 firebase API gs://<MY DOMAIN>/figure_images/SWBS6I_100300_PrimaryFrontImage_Small.jpg

的 follownig url 检索的
2021-01-02 11:41:50.776056-0500 xxx[xxx] Task <xxx>.<87> finished with error [-1002] Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo={NSLocalizedDescription=unsupported URL,NSErrorFailingURLStringKey=SWBS6I_116300_PrimaryFrontImage_Small.jpg,NSErrorFailingURLKey=SWBS6I_116300_PrimaryFrontImage_Small.jpg,_NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <xxx>.<87>"
),_NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <xxx>.<87>,NSUnderlyingError=0x2800c0840 {Error Domain=kCFErrorDomainCFNetwork Code=-1002 "(null)"}}

崩溃时出错

iPhone quit unexpectedly.
Domain: IDEDebugSessionErrorDomain
Code: 4
Failure Reason: Message from debugger: Terminated due to memory issue
--


System Information

macOS Version 11.1 (Build 20C69)
Xcode 12.3 (17715) (Build 12C33)
Timestamp: 2021-01-02T11:44:56-05:00

SwiftUI 视图

import SwiftUI
import struct Kingfisher.KFImage

struct SeriesView: View {

// Firebase auth
@EnvironmentObject var authState: AuthenticationState

// Listen for view model state changes,i.e. series
@ObservedObject var seriesList = seriesListSharedData

var showFigures: [Figure] {
    let showFiguresFilter: [Figure] = seriesList.figureArray.filter({$0.seriesUniqueId == SeriesUniqueIdEnum.SWBS6I})

    return showFiguresFilter
}

// view body
var body: some View {
    ScrollView {
        LazyVGrid(columns: [
            GridItem(.adaptive(minimum: 100,maximum: 100))
        ],content: {
            ForEach(showFigures,id: \.self) { figure in
                FigurePhoto(figure: figure)
            }
        })
    }
}
}

struct FigurePhoto: View {
@ObservedObject var figure: Figure

var body: some View {
    
    // name photo and specifics
    VStack(alignment: .center,spacing: 4) {
        // image and specifics
        HStack(alignment: .top,spacing: 4) {
            VStack(alignment: .center,spacing: 0) {
                let image = figure.imagePrimaryFrontString ?? ""
                KFImage(URL(string: image))
                    .resizable()
                    .aspectRatio(1,contentMode: .fill)
                Spacer()
            } // end vstack
            .onAppear() {
                // (1) WORKS! - Call to flickr function works fine ~ 140MB
                figure.fetchFlickrImageURL(withTags: figure.figureGlobalUniqueId,withText: "\(figure.figureGlobalUniqueId)\(kPrimaryFrontImageNameSuffix)\(kSmallSuffix)")
                // One call OR the other,not both
                // (2) MEMORY ISSUE - Call to firebase function retains memory of every photo whether in view or not until the app crashes ~3GB
                figure.fetchFirebasePrimaryFrontImageString(firebaseStorageRef: kFigureImageRoot)
            } // end vstack on appear
        } // end hstack
    } // end vstack
} // end body
}

按预期管理内存的 Flickr 函数,滚动时释放内存

// fetch all flickr photo images - set the primary photo as the first photo
func fetchFlickrImageURL(withTags tags: String,withText text: String?) {
    
    var stringURL = String()
    
    let flickr = Flickr()
    
    flickr.flickrPhotosSearch(withTags: tags,withText: text) {
        results,error in
        
        if let error = error {
            print("Error searching Flickr: \(error)")
        }
        
        if let results = results {
            
            // check for no photos
            if results.searchResults.count == 0 {
                return
            }
            
            for flickrPhoto in results.searchResults {
                // set front image if text is front image
                if let text = text {
                    // insert the primary image at the beginning
                    if let farm = flickrPhoto.farm,let server = flickrPhoto.server,let secret = flickrPhoto.secret {
                        if text.contains(("\(kPrimaryFrontImageNameSuffix)\(kSmallSuffix)")) {
                            stringURL = "https://farm\(farm).staticflickr.com/\(server)/\(flickrPhoto.photoID)_\(secret).jpg"
                        }
                        else {
                            stringURL = "https://farm\(farm).staticflickr.com/\(server)/\(flickrPhoto.photoID)_\(secret).jpg"
                        }
                    }
                }
            }
            
            self.imagePrimaryFrontString = stringURL
        }
    }
}

滚动时不释放内存的 Firebase 函数

func fetchFirebasePrimaryFrontImageString(firebaseStorageRef: String) {
    let storage = Storage.storage()
    
    // set the image locataion
    getFirebasePrimaryFrontImageString()
    
    // set the image
    let storageRefImage = storage.reference().child(firebaseStorageRef)
    let seriesImageRef = storageRefImage.child(self.imagePrimaryFrontString!)
    
    seriesImageRef.downloadURL { firebaseImageURL,error in
      if let error = error {
        #if DEBUG
        print("ERROR: Failure getting Firebase Series image: \(error.localizedDescription)")
        #endif
      }
      else
      {
        self.imagePrimaryFrontString = firebaseImageURL!.absoluteString
      }
    }
}

func getFirebasePrimaryFrontImageString() {
    self.imagePrimaryFrontString = "\(self.figureGlobalUniqueId)\(kPrimaryFrontImageNameSuffix)\(kSmallSuffix).\(kImageJpgExt)"
}

Flickr 实际调用

    func flickrPhotosSearch(withTags tags: String,withText text: String? = nil,completion : @escaping (_ results: FlickrSearchResults?,_ error : NSError?) -> Void) {
    var searchURL: URL
    
    // check for name passed for front image
    if let text = text {
        guard let searchURLText = flickrSearch(withText: text) else {
            let APIError = NSError(domain: "FlickrSearch",code: 0,userInfo: [NSLocalizedFailureReasonErrorKey:"Unknown API response"])
            completion(nil,APIError)
            return
        }
        
        searchURL = searchURLText
    } else {
        guard let searchURLTags = flickrSearch(withTags: tags) else {
            let APIError = NSError(domain: "FlickrSearch",APIError)
            return
        }
        
        searchURL = searchURLTags
    }
    
    let searchRequest = URLRequest(url: searchURL)
    
    URLSession.shared.dataTask(with: searchRequest,completionHandler: { (data,response,error) in
        
        if let _ = error {
            let APIError = NSError(domain: "FlickrSearch",userInfo: [NSLocalizedFailureReasonErrorKey:"Unknown API response"])
            OperationQueue.main.addOperation({
                completion(nil,APIError)
            })
            return
        }
        
        guard let _ = response as? HTTPURLResponse,let data = data else {
                let APIError = NSError(domain: "FlickrSearch",userInfo: [NSLocalizedFailureReasonErrorKey:"Unknown API response"])
                OperationQueue.main.addOperation({
                    completion(nil,APIError)
                })
                return
        }
        
        do {
            
            guard let resultsDictionary = try JSONSerialization.jsonObject(with: data,options: JSONSerialization.ReadingOptions(rawValue: 0)) as? [String: AnyObject],let stat = resultsDictionary["stat"] as? String else {
                    
                    let APIError = NSError(domain: "FlickrSearch",userInfo: [NSLocalizedFailureReasonErrorKey:"Unknown API response"])
                    OperationQueue.main.addOperation({
                        completion(nil,APIError)
                    })
                    return
            }
            
            switch (stat) {
            case "ok":
                break
            case "fail":
                if let message = resultsDictionary["message"] {
                    
                    let APIError = NSError(domain: "FlickrSearch",userInfo: [NSLocalizedFailureReasonErrorKey:message])
                    
                    OperationQueue.main.addOperation({
                        completion(nil,APIError)
                    })
                }
                
                let APIError = NSError(domain: "FlickrSearch",userInfo: nil)
                
                OperationQueue.main.addOperation({
                    completion(nil,APIError)
                })
                
                return
            default:
                let APIError = NSError(domain: "FlickrSearch",APIError)
                })
                return
            }
            
            guard let photosContainer = resultsDictionary["photos"] as? [String: AnyObject],let photosReceived = photosContainer["photo"] as? [[String: AnyObject]] else {
                
                let APIError = NSError(domain: "FlickrSearch",APIError)
                })
                return
            }
            
            var flickrPhotos = [FlickrPhoto]()
            
            for photoObject in photosReceived {
                guard let photoID = photoObject["id"] as? String,let farm = photoObject["farm"] as? Int,let server = photoObject["server"] as? String,let secret = photoObject["secret"] as? String,let originalSecret = photoObject["originalsecret"] as? String else {
                        break
                }
                
                let flickrPhoto = FlickrPhoto(photoID: photoID,farm: farm,server: server,secret: secret,originalSecret: originalSecret)
                flickrPhotos.append(flickrPhoto)
                
                // thumbnail image
                guard let url = flickrPhoto.flickrImageURL(),let imageData = try? Data(contentsOf: url as URL) else {
                        break
                }
                
                if let image = UIImage(data: imageData) {
                    flickrPhoto.thumbnail = image
                }
            }
            
            OperationQueue.main.addOperation({
                completion(FlickrSearchResults(searchTerm: tags,searchResults: flickrPhotos),nil)
            })
            
        } catch _ {
            completion(nil,nil)
            return
        }
        
        
    }) .resume()
}

Firebase POD 签名和来自 FIRStorageReference 的评论@see https://cloud.google.com/storage/

    /**
 * Asynchronously retrieves a long lived download URL with a revokable token.
 * This can be used to share the file with others,but can be revoked by a developer
 * in the Firebase Console if desired.
 * @param completion A completion block that either returns the URL on success,* or an error on failure.
 */
open func downloadURL(completion: @escaping (URL?,Error?) -> Void)

调试时将我带到这里:

- (void)downloadURLWithCompletion:(FIRStorageVoidURLError)completion {
  FIRStorageGetDownloadURLTask *task =
  [[FIRStorageGetDownloadURLTask alloc] initWithReference:self
                                           fetcherService:_storage.fetcherServiceForApp
                                            dispatchQueue:_storage.dispatchQueue
                                               completion:completion];
  [task enqueue];
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-