我(几乎)成功地实现了 URLSessionDelegate、URLSessionTaskDelegate 和 URLSessionDataDelegate,这样我就可以在后台上传我的对象了。但是我不确定如何实现完成处理程序,以便在服务器返回时删除我发送的对象 statuscode=200
我目前像这样启动uploadTask
let configuration = URLSessionConfiguration.background(withIdentifier: "com.example.myObject\(myObject.id)")
let backgroundSession = URLSession(configuration: configuration,
delegate: CustomDelegate.sharedInstance,
delegateQueue: nil)
let url: NSURL = NSURL(string: "https://www.myurl.com")!
let urlRequest = NSMutableURLRequest(url: url as URL)
urlRequest.httpMethod = "POST"
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let uploadTask = backgroundSession.uploadTask(with: urlRequest as URLRequest, fromFile: path)
uploadTask.resume()
我尝试在 uploadTask 的初始化中添加一个闭包,但 xcode 显示一个错误,表明这是不可能的。
我有我的自定义类 CustomDelegate:
class CustomDelegate : NSObject, URLSessionDelegate, URLSessionTaskDelegate, URLSessionDataDelegate {
static var sharedInstance = CustomDelegate()
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
print("\(session.configuration.identifier!) received data: \(data)")
do {
let parsedData = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:Any]
let status = parsedData["status"] as! NSDictionary
let statusCode = status["httpCode"] as! Int
switch statusCode {
case 200:
// Do something
case 400:
// Do something
case 401:
// Do something
case 403:
// Do something
default:
// Do something
}
}
catch {
print("Error parsing response")
}
}
}
它还为委托(delegate)实现其他功能。
我想要的是以某种方式知道上传已完成,以便我可以从 CustomDelegate 中更新我觉得很难(也许不可能?)的 UI 和数据库。
最佳答案
如果您只对检测请求的完成感兴趣,最简单的方法是使用闭包:
class CustomDelegate : NSObject, URLSessionDelegate, URLSessionTaskDelegate, URLSessionDataDelegate {
static var sharedInstance = CustomDelegate()
var uploadDidFinish: ((URLSessionTask, Error?) -> Void)?
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
DispatchQueue.main.async {
uploadDidFinish?(task, error)
}
}
}
然后你的 View Controller 会在发起请求之前设置这个闭包,例如
CustomDelegate.sharedInstance.uploadDidFinish = { [weak self] task, error in
// update the UI for the completion here
}
// start the request here
如果您想在多种情况下更新您的 UI(例如,不仅在上传完成时,而且在上传发送时有进展),理论上您可以设置多个关闭(一个用于完成,一个用于进度),但通常您d 采用你自己的委托(delegate)协议(protocol)模式。 (就个人而言,我会将 CustomDelegate 重命名为 UploadManager 之类的名称,以避免混淆谁是什么的委托(delegate),但这取决于您。)
例如你可能会这样做:
protocol UploadDelegate: class {
func didComplete(session: URLSession, task: URLSessionTask, error: Error?)
func didSendBodyData(session: URLSession, task: URLSessionTask, bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64)
}
然后,在您的网络请求管理器(您的CustomDelegate 实现)中,定义一个delegate 属性:
weak var delegate: UploadDelegate?
在适当的 URLSession 委托(delegate)方法中,您将调用自定义委托(delegate)方法将信息传递给 View Controller :
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
// do whatever you want here
DispatchQueue.main.async {
delegate?.didComplete(session: session, task: task, didCompleteWithError: error)
}
}
func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {
// do whatever you want here
DispatchQueue.main.async {
delegate?.didSendBodyData(session: session, task: task, bytesSent: bytesSent, totalBytesSent: totalBytesSent, totalBytesExpectedToSend: totalBytesExpectedToSend)
}
}
然后,您将声明您的 View Controller 以符合您的新协议(protocol)并实现这些方法:
class ViewController: UIViewController, UploadDelegate {
...
func startRequests() {
CustomDelegate.sharedInstance.delegate = self
// initiate request(s)
}
func didComplete(session: URLSession, task: URLSessionTask, error: Error?) {
// update UI here
}
func didSendBodyData(session: URLSession, task: URLSessionTask, bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {
// update UI here
}
}
现在,您可以更新此 UploadDelegate 协议(protocol)以捕获模型信息并将其作为参数传递给您的方法,但希望这能说明基本思想。
一些小观察:
创建 session 时,您可能应该从代码中删除 NSURL 和 NSMutableURLRequest 类型,例如:
let url = URL(string: "https://www.myurl.com")!
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let uploadTask = backgroundSession.uploadTask(with: urlRequest, fromFile: path)
uploadTask.resume()
您正在 didReceiveData 中寻找 statusCode。您确实应该在 didReceiveResponse 中这样做。此外,您通常会从 URLResponse 中获取状态代码。
您正在解析 didReceiveData 中的响应。通常,您应该在 didCompleteWithError 中执行此操作(以防需要多次调用 didReceiveData 才能接收整个响应)。
我不知道这个 myObject.id 是什么,但是你选择的标识符,"com.example.myObject\(myObject.id)",有点可疑:
您是否正在为每个对象创建一个新的 URLSession 实例?您可能需要一个来满足所有请求。
当您的应用暂停/放弃而上传在后台继续进行时,当应用重新启动时,您是否有可靠的方法来重新实例化相同的 session 对象?
通常,您希望所有上传都使用一个上传 session ,并且名称应该保持一致。我并不是说您不能按照您的方式进行操作,但似乎在不进行一些额外工作的情况下重新创建这些 session 会出现问题。这取决于你。
所有这一切都是说,如果应用程序终止并在上传完成后在后台重新启动,我会确保您测试后台上传过程是否正常。感觉这是不完整/脆弱的,但希望我只是跳到一些不正确的结论,你已经完成了所有工作,只是没有分享一些细节(例如你的应用委托(delegate)的 handleEventsForBackgroundURLSession)为了简洁起见(非常感谢)。
关于swift - 为 backgroundSession.uploadTask 实现完成处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40657262/
我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
我想用ruby编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序
我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
如何检查Ruby文件是否是通过“require”或“load”导入的,而不是简单地从命令行执行的?例如:foo.rb的内容:puts"Hello"bar.rb的内容require'foo'输出:$./foo.rbHello$./bar.rbHello基本上,我想调用bar.rb以不执行puts调用。 最佳答案 将foo.rb改为:if__FILE__==$0puts"Hello"end检查__FILE__-当前ruby文件的名称-与$0-正在运行的脚本的名称。 关于ruby-检查是否
是否可以在应用程序中包含的gem代码中知道应用程序的Rails文件系统根目录?这是gem来源的示例:moduleMyGemdefself.included(base)putsRails.root#returnnilendendActionController::Base.send:include,MyGem谢谢,抱歉我的英语不好 最佳答案 我发现解决类似问题的解决方案是使用railtie初始化程序包含我的模块。所以,在你的/lib/mygem/railtie.rbmoduleMyGemclassRailtie使用此代码,您的模块将在