属性初始化器在self前执行时,如何调用实例方法生成CGImage?
解决「Cannot use instance member within property initializer」错误
错误原因
你遇到的报错核心逻辑是:类的存储属性初始化代码会在self实例完全创建之前执行,而makeRandomImage是实例方法,必须依托已初始化完成的self才能调用,因此直接在属性初始化阶段调用该方法会触发这个错误。
解决方案
以下是三种可行的修复方式,根据你的业务场景选择即可:
方案1:使用懒加载属性(推荐)
将cgImage和uiImage声明为lazy var,这样它们会在第一次被访问时才完成初始化,此时self已经完全可用,就能正常调用实例方法:
import SwiftUI import Accelerate class ImageClassifier: ObservableObject { @Published private var classifier = Classifier() var imageClass: String? { classifier.results } func makeRandomImage(width: Int, height: Int) -> CGImage? { let imageFormat = vImage_CGImageFormat( bitsPerComponent: 8, bitsPerPixel: 8 * 3, colorSpace: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue))! let arrayDescriptor = BNNSNDArrayDescriptor.allocate( randomIn: Pixel_8(0) ... 255, shape: .matrixRowMajor(width * imageFormat.componentCount, height)) let imageBuffer = vImage_Buffer(data: arrayDescriptor.data, height: vImagePixelCount(height), width: vImagePixelCount(width), rowBytes: width) return try? imageBuffer.createCGImage(format: imageFormat) } // 延迟初始化,第一次访问时self已完成初始化 lazy var cgImage = makeRandomImage(width: 1024, height: 1024)! lazy var uiImage = UIImage(cgImage: cgImage) // MARK: Intent(s) // 修正参数类型为UIImage(原代码写的uiImage是变量名,不是类型) func detect(uiImage: UIImage) { guard let ciImage = CIImage(image: uiImage) else { return } classifier.detect(ciImage: ciImage) } }
方案2:在初始化方法中赋值
如果需要在实例创建时就完成属性初始化,可以把属性声明为隐式解包可选类型,然后在init方法中调用赋值:
import SwiftUI import Accelerate class ImageClassifier: ObservableObject { @Published private var classifier = Classifier() var imageClass: String? { classifier.results } // 声明为隐式解包可选类型 var cgImage: CGImage! var uiImage: UIImage! func makeRandomImage(width: Int, height: Int) -> CGImage? { // 原方法代码不变 let imageFormat = vImage_CGImageFormat( bitsPerComponent: 8, bitsPerPixel: 8 * 3, colorSpace: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue))! let arrayDescriptor = BNNSNDArrayDescriptor.allocate( randomIn: Pixel_8(0) ... 255, shape: .matrixRowMajor(width * imageFormat.componentCount, height)) let imageBuffer = vImage_Buffer(data: arrayDescriptor.data, height: vImagePixelCount(height), width: vImagePixelCount(width), rowBytes: width) return try? imageBuffer.createCGImage(format: imageFormat) } init() { // init方法中self已完成初始化,可调用实例方法 cgImage = makeRandomImage(width: 1024, height: 1024)! uiImage = UIImage(cgImage: cgImage) } func detect(uiImage: UIImage) { guard let ciImage = CIImage(image: uiImage) else { return } classifier.detect(ciImage: ciImage) } }
方案3:将方法改为静态方法
如果makeRandomImage不需要访问任何实例属性,可以把它改成静态方法,这样无需依赖self就能直接调用:
import SwiftUI import Accelerate class ImageClassifier: ObservableObject { @Published private var classifier = Classifier() var imageClass: String? { classifier.results } // 改为static静态方法 static func makeRandomImage(width: Int, height: Int) -> CGImage? { let imageFormat = vImage_CGImageFormat( bitsPerComponent: 8, bitsPerPixel: 8 * 3, colorSpace: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue))! let arrayDescriptor = BNNSNDArrayDescriptor.allocate( randomIn: Pixel_8(0) ... 255, shape: .matrixRowMajor(width * imageFormat.componentCount, height)) let imageBuffer = vImage_Buffer(data: arrayDescriptor.data, height: vImagePixelCount(height), width: vImagePixelCount(width), rowBytes: width) return try? imageBuffer.createCGImage(format: imageFormat) } // 调用静态方法,无需self let cgImage = ImageClassifier.makeRandomImage(width: 1024, height: 1024)! let uiImage = UIImage(cgImage: cgImage) func detect(uiImage: UIImage) { guard let ciImage = CIImage(image: uiImage) else { return } classifier.detect(ciImage: ciImage) } }
内容的提问来源于stack exchange,提问作者ColorTheory42
相关产品推荐
相关产品推荐

