使用 MTKTextureLoader 加载远程图像

Load a remote image using MTKTextureLoader

我正在尝试使用此代码将远程图像加载到 MTLTexture 中,

    let textureLoader = MTKTextureLoader(device: device)
    textureLoader.newTexture(withContentsOf: url, options: options) { [weak self] (texture, error) in
        if let t = texture {
            completion(t)
        } else {
            if let desc = error?.localizedDescription {
                NSLog(desc)
            }
            completion(nil)
        }
    }

如果 URL 来自 Bundle 资源,那么它可以工作,例如

let url = Bundle.main.url(forResource: name, withExtension: ext)

但是,如果我通过这样的东西,它会失败,

let url = URL(string: "http://example.com/images/bla_bla.jpg")

出现这个错误,

Could not find resource bla_bla.jpg at specified location.

如果我将 url 复制粘贴到浏览器中,则图像显示没有问题(另外我在 Android 中使用 OpenGL 实现了同样的事情并且图像渲染正常)。

我已将我的域添加到 Info.plist,我可以从该位置加载 Json 之类的内容。只是纹理加载器很有趣... Info.plist 看起来像这样,

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <false/>
    <key>NSExceptionDomains</key>
    <dict>
        <key>example.com</key>
        <dict>
            <key>NSIncludesSubdomains</key>
            <true/>
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <key>NSTemporaryExceptionMinimumTLSVersion</key>
            <string>TLSv1.1</string>
        </dict>
    </dict>
</dict>

MTKTextureLoader documentation没有提到任何关于外部URL的东西,难道它只处理内部资源吗?

下面是一个示例,说明如何扩展 MTKTextureLoader 以加载默认实现不支持的远程 URL。

extension MTKTextureLoader {
    enum RemoteTextureLoaderError: Error {
        case noCachesDirectory
        case downloadFailed(URLResponse?)
    }

    func newTexture(withContentsOfRemote url: URL, options: [String : NSObject]? = nil, completionHandler: @escaping MTKTextureLoaderCallback) {
        let downloadTask = URLSession.shared.downloadTask(with: URLRequest(url: url)) { (maybeFileURL, maybeResponse, maybeError) in
            var anError: Error? = maybeError
            if let tempURL = maybeFileURL, let response = maybeResponse {
                if let cachePath = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first {
                    let cachesURL = URL(fileURLWithPath: cachePath, isDirectory: true)
                    let cachedFileURL = cachesURL.appendingPathComponent(response.suggestedFilename ?? NSUUID().uuidString)
                    try? FileManager.default.moveItem(at: tempURL, to: cachedFileURL)
                    return self.newTexture(withContentsOf: cachedFileURL, options: options, completionHandler: completionHandler)
                } else {
                    anError = RemoteTextureLoaderError.noCachesDirectory
                }
            } else {
                anError = RemoteTextureLoaderError.downloadFailed(maybeResponse)
            }
            completionHandler(nil, anError)
        }
        downloadTask.resume()
    }
}

理想情况下,您应该实施自己的缓存机制以避免重复下载相同的图像,但这应该能让您入门。