Привет, я новичок здесь и очень новичок в программировании, но постараюсь прояснить этот вопрос настолько, насколько это возможно. По сути, у меня есть таблица, созданная из запроса SQL, которая дает список предметов / объектов в инвентаризации пользователя на основе их идентификатора пользователя. Таблица выглядит примерно так (где userID равен 5). Приносим свои извинения, так как мне не хватает представителя для публикации фотографий:
инвентарь пользователя 5
Я собирался иметь tableView в Swift, чтобы заполнить эту таблицу, но когда я столкнулся с проблемами с преобразованием ответа, я вместо этого просто создал отдельный ViewController с кнопкой для запуска функции checkInventory, чтобы я мог распечатать все данные и посмотреть, где вопрос есть.
Сначала вот моя PHP функция для проверки инвентаря:
public function getUserInventory($userID) {
$returnValue = array();
$sql = "select aObjects.objectID, objectDescription from aUsers join aInventory on aUsers.userID = aInventory.userID join aObjects on aInventory.objectID = aObjects.objectID where aUsers.userID='" .$userID. "'" ;
try {
$statement = $this->conn->prepare($sql);
$statement->execute();
$statement->bind_result($objectID, $objectDescription);
}
catch (PDOException $e)
{
print $e->getMessage();
}
$result = $statement->get_result();
if ($result != null && (mysqli_num_rows($result) >= 1))
{
$row = $result->fetch_all(MYSQLI_ASSOC);
if (!empty($row)) {
$returnValue = $row;
}
}
return $returnValue;
}
Строка исключения PDO может быть ненужной / неправильной, потому что я использую mysqli, но независимо от этого здесь есть другой файл PHP, который вызывает эту функцию:
<?php
set_include_path('.:/testservice/');
$data = json_decode(file_get_contents('php://input'), true);
$userID = $data["userID"];
//$userID = htmlentities($_GET["userID"]); <--- for testing
include 'Conn.php'; /* connection file */
include 'aSQLDao.php'; /* rest of php file */
$dao = new aSQLDao();
$dao->openConnection();
$userInventory = $dao->getUserInventory($userID);
echo json_encode($userInventory);
return;
$dao->closeConnection();
?>
Я на 90% уверен, что корень моей проблемы заключается в том, что мой PHP не выдает вывод JSON, который Swift может правильно прочитать. Когда я использую почтальон для проверки PHP с userID = 5, я получаю объект, который выглядит красиво, но, похоже, имеет основную проблему с его форматом:
[
{
"objectID": 1,
"objectDescription": "alien"},
{
"objectID": 2,
"objectDescription": "forestMonster"},
{
"objectID": 10,
"objectDescription": "tank"},
{
"objectID": 9,
"objectDescription": "fish"}
]
В swift я только что установил переменную userID равной 5, чтобы протестировать ее, и прошел общий процесс запроса + сериализации:
@IBAction func inventoryButtonTapped(_ sender: Any) {
let userID = "5"let myURL = URL(string: "http://myIP/testservice/inventoryCheck.php");
var request = URLRequest(url:myURL!);
request.httpMethod = "GET"request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
let getString = ["userID": userID] as [String: String]
do {
request.httpBody = try JSONSerialization.data(withJSONObject: getString, options: .prettyPrinted)
} catch let error {
print(error.localizedDescription)
displayMessage(userMessage: "Something went wrong")
return
}
let task = URLSession.shared.dataTask(with: request) {
data, response, error in
if error != nil {
self.displayMessage(userMessage: "Could not perform")
print("error=\(String(describing: error))")
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSDictionary
print(json)
Это еще не все, но на основе точек останова я не могу правильно преобразовать эти данные на этапе JSONSerialization. При использовании «as! NS Dictionary» я получаю «Не удалось привести значение типа ‘__NSArrayM’ (0x10ad29a88) к ‘NSDictionary’ (0x10ad2b1a8).» ошибка.
При использовании «as! NSArray» я получаю пустой набор паратезов. Я попытался также использовать Array>, что привело к пустому набору скобок. Я также попытался установить userID в int, но из того, что я прочитал, это не должно влиять.
Я прошу прощения, если здесь отсутствуют какие-либо детали. Так как это кажется довольно простым случаем переноса таблицы SQL в UITableView, я предполагаю, что я либо пропускаю основную часть, либо выполняю неправильный набор операций.
ОБНОВЛЕНИЕ: я выяснил, что Сервер просто не получает мой ключ userID правильно, что странно, но, по крайней мере, мы надеемся, что PHP или Swift неверны — предположим, что оба предоставленных ответа будут работать, если переменная была правильно отправлена в скрипт
РЕШЕНО: По какой-то причине эта проблема была решена при изменении HTTPRequest с GET на POST — казалось, проблема с вводом PHP, не работающим для запроса GET. Я обновлю этот пост более конкретными деталями для дальнейшего использования, когда выясню, как заставить запрос GET работать должным образом, поскольку это должен быть GET, а не POST. Оба предоставленных ответа верны с точки зрения изменения NSDictionary на NSArray или [[String: Any]]
Линия десериализации находится здесь:
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSDictionary
Вы пытаетесь принудительно привести к NSDictionary. Проблема в том, что ваша структура данных является массивом.
[ // this will convert to an array
{ // this will convert to a dictionary
"objectID": 1,
"objectDescription": "alien"},
...
]
У вас есть пара вариантов. Вы можете изменить ее JSON для создания словаря или изменить десериализатор для получения массива.
Вот второй случай в коде:
//: Playground - noun: a place where people can play
import UIKit
var dataStr = """[ { "objectID": 1, "objectDescription": "alien" }, { "objectID": 2, "objectDescription": "forestMonster" }, { "objectID": 10, "objectDescription": "tank" }, { "objectID": 9, "objectDescription": "fish" }]
"""var data = dataStr.data(using: .utf8)
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSArray
И результат:
Я думаю, что вы должны сначала привести в порядок свой код JSON-разбора, прежде чем начинать разбираться с dataTask
и тому подобное. Бросив в некоторых Codable
чтобы стать более быстрым, вы получите что-то вроде
import Cocoa
let jsonData = """[
{
"objectID": 1,
"objectDescription": "alien"},
{
"objectID": 2,
"objectDescription": "forestMonster"},
{
"objectID": 10,
"objectDescription": "tank"},
{
"objectID": 9,
"objectDescription": "fish"}
]
""".data(using: .utf8)!
struct MyObject: Codable {
let id: Int
let description: String
private enum CodingKeys: String, CodingKey {
case id = "objectID"case description = "objectDescription"}
}
do {
let obj = try JSONDecoder().decode([MyObject].self, from:jsonData)
print(obj)
} catch {
print(error)
}
Это даст вам гораздо больше удобных объектов Swift с минимальными усилиями и JSONDecoder
обычно говорит вам, если что-то не так с доставленным JSON (чего нет в данном случае).
Имея это в виду, вы должны распечатать ваши необработанные данные (преобразовав их в String
перед тем как сделать это) чтобы узнать что вы кидаете в свой парсер (JSONDecoder
).