我通过 POST
将带有图片的文本发送到服务器。文字正确,但图片不完整。 10%的图片显示正确,其他的只是灰色背景。 Swift
使用 base64EncodedString()
将图像文件转换为文本。
似乎Swift
执行转换有错误,或者服务器没有完全接收到数据。但是我增加了 POST
的限制,但没有帮助。我还使用 compressionQuality
更改了图像压缩值,但没有帮助。
来自视图文件的代码:
Button(action: {
self.checkBoxStatus = false
let uiImage: UIImage = self.selectedImage.asUIImage()
let imageData: Data = uiImage.jpegData(compressionQuality: 0.9) ?? Data()
let imageStr: String = imageData.base64EncodedString()
let shareHelper = ShareHelper(message: validateForm.content, user: validateForm.user, email: validateForm.email, media: imageStr)
shareHelper.RequestPost { (dataString) in
self.checkRequestStatus = true
validateForm.content = ""
validateForm.user = ""
validateForm.email = ""
validateForm.media = ""
self.selectedImage = Image("")
}
}, label: {
Text("Send")
})
如何解决?
附注:
POST
请求代码:
import Foundation
class ShareHelper {
var dataString: String = ""
var newsMessage: String
var newsUser: String
var newsEmail: String
var newsMedia: String
let newsAPI: String = "https://example.com/api/shareNews"
init(message: String, user: String, email: String, media: String) {
self.newsMessage = message
self.newsUser = user
self.newsEmail = email
self.newsMedia = media
}
func RequestPost(completion: @escaping((String) -> Void)) {
let url = URL(string: self.newsAPI)
guard let requestUrl = url else { fatalError() }
var request = URLRequest(url: requestUrl)
request.httpMethod = "POST"
let postString = "message=\(self.newsMessage)&user=\(self.newsUser)&email=\(self.newsEmail)&media=\(self.newsMedia)"
request.httpBody = postString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if error != nil {
return
}
if let data = data, let dataString = String(data: data, encoding: .utf8) {
DispatchQueue.main.async {
self.dataString = dataString
completion(dataString)
}
}
}
task.resume()
}
}
答案 0 :(得分:1)
我在此线程中看到了一些解决您问题的方法 How to upload images to a server in iOS with Swift?
在此线程中还有一些答案演示了如何通过 POST 方法将图像上传到服务器。
答案 1 :(得分:1)
最好的做法是提供一个只上传图片的上传api。您可以使用多部分 POST 来完成它。然后获取带有上传图片 ID 的响应,并将其添加到您的 shareNews
api 请求中。
服务端应该通过 id 来管理图片。
对于您当前的代码,我想它运行良好,请尝试询问后端开发人员他们如何解码您的 base64-ed 数据。
答案 2 :(得分:1)
您可以使用使用 SerialQueue 的组合框架,并将您的图像与与您的新闻相关的数据分开发送。
所以这是按住按钮的 SwiftUI 视图。你会注意到我引入了一个视图模型来避免视图内部的任何逻辑。
import SwiftUI
struct ContentView: View {
/// Used to separate the logic from the view.
@ObservedObject var viewModel = ContentViewModel()
var body: some View {
Button(action: { viewModel.sendNewsData() }) {
Text("Send")
}
}
}
所以这是视图模型本身,发送数据的逻辑发生在这里。您将不得不单独处理发送新闻数据。如果您在使用 Combine 时需要一些帮助,只需在 StackOverflow 上提出一个新问题即可。
import Combine
import SwiftUI
final class ContentViewModel: ObservableObject {
let networkRequestManager = NetworkRequestManager()
let image = UIImage(named: "MySpecialImage")! // The image you want to send
var cancellables = Set<AnyCancellable>()
/// Send the news data and the image in one function
/// to be used in your SwiftUI view.
func sendNewsData() {
postImageData(of: image)
postNewsData()
}
/// Send the image on its own method.
///
/// The data encoded string printed is related
/// to your image that comes back from the api.
func postImageData(of image: UIImage) {
networkRequestManager
.sendImage(image)
.sink(
receiveCompletion: { completion in
print(completion) },
receiveValue: { data in
print(data) }) // your image
.store(in: &cancellables)
}
func postNewsData() {
// Just post your news data without the image
// for it to be sent separately.
}
}
所以这里是 NetworkRequestManager
类,它处理将编码为字符串的图像发送到您的 api 端点。只需根据需要更改 url。
不要忘记将与图像关联的密钥更改为 api 中的相关密钥。如果您需要使用组合和缓存系统取回图像的解决方案,只需在 StackOverflow 上提出一个新问题即可。
import Combine
import SwiftUI
final class NetworkRequestManager {
/// Send the image in a serial queue to not obstruct the main queue.
let imageSerialQueue = DispatchQueue(label: "imageSerialQueue")
/// This is where you will encode your image data to send it to your api.
func sendImage(_ image: UIImage) -> AnyPublisher<String, Error> {
let url = URL(string: "https://example.com/api/shareNews")!
let body = setupBody(with: image)
let urlRequest = setupURLRequest(url: url, body: body)
return URLSession.shared
.dataTaskPublisher(for: urlRequest)
.subscribe(on: imageSerialQueue)
.map { $0.data }
.encode(encoder: JSONEncoder())
.decode(type: String.self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
/// The body related to your endpoint.
///
/// Make sure that the dictionary key matches the one in your api.
func setupBody(with image: UIImage) -> [String: Any] {
let jpegData = image.jpegData(compressionQuality: 1)
return ["newsMedia": jpegData?.base64EncodedString() as Any]
}
/// Setup the url request to send a POST method with your image
/// in a json format.
func setupURLRequest(url: URL,
body: [String: Any]) -> URLRequest {
var urlRequest = URLRequest(url: url)
urlRequest.allowsConstrainedNetworkAccess = true
urlRequest.httpMethod = "POST"
urlRequest.setValue("application/json",
forHTTPHeaderField: "Content-Type")
urlRequest.httpBody = try? JSONSerialization.data(withJSONObject: body)
return urlRequest
}
}