- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我尝试使用 URLSession.shared.dataTask 从服务器获取一些数据。它工作正常,但我不能像类变量一样保存结果。许多答案建议使用completion Handler,但这对我的任务没有帮助。
这是我的测试代码:
class PostForData {
func forData(completion: @escaping (String) -> ()) {
if let url = URL(string: "http://odnakrov.info/MyWebService/api/test.php") {
var request = URLRequest(url: url)
request.httpMethod = "POST"
let postString : String = "json={\"Ivan Bolgov\":\"050-062-0769\"}"
print(postString)
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) {
data, response, error in
let json = String(data: data!, encoding: String.Encoding.utf8)!
completion(json)
}
task.resume()
}
}
}
class ViewController: UIViewController {
var str:String?
override func viewDidLoad() {
super.viewDidLoad()
let pfd = PostForData()
pfd.forData { jsonString in
print(jsonString)
DispatchQueue.main.async {
self.str = jsonString
}
}
print(str ?? "not init yet")
}
}
最佳答案
这个闭包是@escaping
(即后面异步调用的),所以你必须把它放在闭包里面:
class ViewController: UIViewController {
@IBOutlet weak var label: UILabel!
var str: String?
override func viewDidLoad() {
super.viewDidLoad()
let pfd = PostForData()
pfd.performRequest { jsonString, error in
guard let jsonString = jsonString, error == nil else {
print(error ?? "Unknown error")
return
}
// use jsonString inside this closure ...
DispatchQueue.main.async {
self.str = jsonString
self.label.text = jsonString
}
}
// ... but not after it, because the above runs asynchronously (i.e. later)
}
}
请注意,我将您的闭包更改为返回 String?
和 Error?
以便 View Controller 可以知道是否发生了错误(如果它关心,它可以看到发生了什么样的错误)。
请注意,我将您的 forData
重命名为 performRequest
。通常,您会使用比这更有意义的名称,但方法名称(在 Swift 3 及更高版本中)通常应包含一个动词,指示正在做什么。
class PostForData {
func performRequest(completion: @escaping (String?, Error?) -> Void) {
// don't try to build JSON manually; use `JSONSerialization` or `JSONEncoder` to build it
let dictionary = [
"name": "Ivan Bolgov",
"ss": "050-062-0769"
]
let jsonData = try! JSONEncoder().encode(dictionary)
// It's a bit weird to incorporate JSON in `x-www-form-urlencoded` request, but OK, I'll do that.
// But make sure to percent escape it.
let jsonString = String(data: jsonData, encoding: .utf8)!
.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed)!
let body = "json=" + jsonString
let url = URL(string: "http://odnakrov.info/MyWebService/api/test.php")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = body.data(using: .utf8)
// It's not required, but it's good practice to set `Content-Type` (to specify what you're sending)
// and `Accept` (to specify what you're expecting) headers.
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
// now perform the prepared request
let task = URLSession.shared.dataTask(with: request) { data, _, error in
guard let data = data, error == nil else {
completion(nil, error)
return
}
let responseString = String(data: data, encoding: .utf8)
completion(responseString, nil)
}
task.resume()
}
}
该例程也有一些修改,具体是:
永远不要在处理服务器响应时使用 !
强制解包。您无法控制请求是成功还是失败,强制解包运算符会使您的应用程序崩溃。您应该使用 guard let
或 if let
模式优雅地解包这些可选值。
使用 json=...
模式非常不寻常,其中 ...
是 JSON 字符串。可以推断出您正在准备一个 application/x-www-form-urlencoded
请求,并使用 $_POST
或 $_REQUEST
来获取与 json
键关联的值。通常你要么做真正的 JSON 请求,要么你做 application/x-www-form-urlencoded
请求,但不是两者都做。但是在一个请求中执行这两项操作会使客户端和服务器代码的工作量加倍。上面的代码遵循您原始代码片段中的模式,但我建议使用其中之一,但不要同时使用。
就我个人而言,我不会让 performRequest
返回 JSON 字符串。我建议它实际执行 JSON 的解析。但是,我再次将其保留在您的代码片段中。
我注意到您以 "Ivan Bolgov": "050-062-0769"
的形式使用了 JSON。我建议不要使用“值”作为 JSON 的键。键应该是有利地定义的常量。因此,例如,上面我使用了 "name": "Ivan Bolgov"
和 "ss": "050-062-0769"
,服务器知道在哪里寻找名为 name
和 ss
的键。在这里做任何您想做的事,但您的原始 JSON 请求似乎混淆了键(通常事先已知)和值(哪些值与这些键相关联)。
如果您要执行 x-www-form-urlencoded
请求,您必须对提供的值进行百分比编码,就像我在上面所做的那样。值得注意的是,诸如空格字符之类的字符在此类请求中是不允许的,因此您必须对它们进行百分比编码。不用说,如果您执行了正确的 JSON 请求,就不需要这些愚蠢的事情了。
但请注意,当百分比编码时,不要试图使用默认的 .urlQueryAllowed
字符集,因为它会允许某些字符未转义地通过。所以我定义了一个 .urlQueryValueAllowed
,它从 .urlQueryAllowed
字符集中删除了某些字符(改编自 Alamofire 中使用的模式):
extension CharacterSet {
/// Returns the character set for characters allowed in the individual parameters within a query URL component.
///
/// The query component of a URL is the component immediately following a question mark (?).
/// For example, in the URL `http://www.example.com/index.php?key1=value1#jumpLink`, the query
/// component is `key1=value1`. The individual parameters of that query would be the key `key1`
/// and its associated value `value1`.
///
/// According to RFC 3986, the set of unreserved characters includes
///
/// `ALPHA / DIGIT / "-" / "." / "_" / "~"`
///
/// In section 3.4 of the RFC, it further recommends adding `/` and `?` to the list of unescaped characters
/// for the sake of compatibility with some erroneous implementations, so this routine also allows those
/// to pass unescaped.
static var urlQueryValueAllowed: CharacterSet = {
let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4
let subDelimitersToEncode = "!$&'()*+,;="
var allowed = CharacterSet.urlQueryAllowed
allowed.remove(charactersIn: generalDelimitersToEncode + subDelimitersToEncode)
return allowed
}()
}
我建议更改您的 PHP 以接受 JSON 请求,例如:
<?php
// read the raw post data
$handle = fopen("php://input", "rb");
$raw_post_data = '';
while (!feof($handle)) {
$raw_post_data .= fread($handle, 8192);
}
fclose($handle);
// decode the JSON into an associative array
$request = json_decode($raw_post_data, true);
// you can now access the associative array how ever you want
if ($request['foo'] == 'bar') {
$response['success'] = true;
$response['value'] = 'baz';
} else {
$response['success'] = false;
}
// I don't know what else you might want to do with `$request`, so I'll just throw
// the whole request as a value in my response with the key of `request`:
$raw_response = json_encode($response);
// specify headers
header("Content-Type: application/json");
header("Content-Length: " . strlen($raw_response));
// output response
echo $raw_response;
?>
然后您可以简化请求的构建,消除我们必须对 x-www-form-urlencoded
请求执行的所有百分比编码的需要:
class PostForData {
func performRequest(completion: @escaping (String?, Error?) -> Void) {
// Build the json body
let dictionary = [
"name": "Ivan Bolgov",
"ss": "050-062-0769"
]
let data = try! JSONEncoder().encode(dictionary)
// build the request
let url = URL(string: "http://odnakrov.info/MyWebService/api/test.php")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = data
// It's not required, but it's good practice to set `Content-Type` (to specify what you're sending)
// and `Accept` (to specify what you're expecting) headers.
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
// now perform the prepared request
let task = URLSession.shared.dataTask(with: request) { data, _, error in
guard let data = data, error == nil else {
completion(nil, error)
return
}
let responseString = String(data: data, encoding: .utf8)
completion(responseString, nil)
}
task.resume()
}
}
关于ios - 从 URLSession 返回数据并保存在属性变量中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48890209/
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: How to nest OR statements in JavaScript? 有没有办法做到这一点:
在 JavaScript 中有没有办法让一个变量总是等于一个变量?喜欢var1 = var2但是当var2更新,也是var1 . 例子 var var1 = document.getElementBy
我正在努力理解这代表什么 var1 = var2 == var3 我的猜测是这等同于: if (var2 == var3): var1 = var2 最佳答案 赋值 var1 = var2
这个问题已经有答案了: What does the PHP error message "Notice: Use of undefined constant" mean? (2 个回答) 已关闭 8
我在临时表中有几条记录,我想从每条记录中获取一个值并将其添加到一个变量中,例如 color | caption -------------------------------- re
如何将字符串转为变量(字符串变量--> $variable)? 或者用逗号分隔的变量列表然后转换为实际变量。 我有 2 个文件: 列名文件 行文件 我需要根据字符串匹配行文件中的整行,并根据列名文件命
我有一个我无法解决的基本 php 问题,我也想了解为什么! $upperValueCB = 10; $passNodeMatrixSource = 'CB'; $topValue= '$uppe
这可能吗? php $variable = $variable1 || $variable2? 如果 $variable1 为空则使用 $variable2 是否存在类似的东西? 最佳答案 PHP 5
在 Perl 5.20 中,for 循环似乎能够修改模块作用域的变量,但不能修改父作用域中的词法变量。 #!/usr/bin/env perl use strict; use warnings; ou
为什么这不起作用: var variable; variable = variable.concat(variable2); $('#lunk').append(variable) 我无法弄清楚这一点
根据我的理解,在32位机器上,指针的sizeof是32位(4字节),而在64位机器上,它是8字节。无论它们指向什么数据类型,它们都有固定的大小。我的计算机在 64 位上运行,但是当我打印包含 * 的大
例如: int a = 10; a += 1.5; 这运行得很完美,但是 a = a+1.5; 此作业表示类型不匹配:无法从 double 转换为 int。所以我的问题是:+= 运算符 和= 运算符
您好,我写了这个 MySQL 存储过程,但我一直收到这个语法错误 #1064 - You have an error in your SQL syntax; check the manual that
我试图在我的场景中显示特定的奖牌,这取决于你的高分是基于关卡的目标。 // Get Medal Colour if levelHighscore goalScore { sc
我必须维护相当古老的 Visual C++ 源代码的大型代码库。我发现代码如下: bIsOk = !!m_ptr->isOpen(some Parameters) bIsOk的数据类型是bool,is
我有一个从 MySQL 数据库中提取的动态产品列表。在 list 上有一个立即联系 按钮,我正在使用一个 jquery Modal 脚本,它会弹出一个表单。 我的问题是尝试将产品信息变量传递给该弹出窗
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: What is the difference between (type)value and type(va
jQuery Core Style Guidelines建议两种不同的方法来检查变量是否已定义。 全局变量:typeof variable === "undefined" 局部变量:variable
这个问题已经有答案了: 已关闭11 年前。 Possible Duplicate: “Variable” Variables in Javascript? 我想肯定有一种方法可以在 JavaScrip
在语句中使用多重赋值有什么优点或缺点吗?在简单的例子中 var1 = var2 = true; 赋值是从右到左的(我相信 C# 中的所有赋值都是如此,而且可能是 Java,尽管我没有检查后者)。但是,
我是一名优秀的程序员,十分优秀!