我已经在一个iPhone应用程序上工作了几个月,该应用程序使用PHP脚本从MYSQL数据库中提取/更新信息,该脚本将任何结果转换为JSON数据。在尝试将我的PHP脚本与我的应用程序集成时,我在接收通过PHP脚本传递回应用程序的JSON数据时遇到一些问题。这是脚本的文本,我已经验证它可以正常工作。
<?php
//Read zip code from POST request
$queryzip = $_POST["ZipID"];
//Create MYSQL connection
$conn = new mysqli("localhost", "root", "Gov4Me", "Gov4Me");
//Check connection
if (mysqli_connect_error()) {
die("Database connection failed: " .mysqli_connect_error());
}
//Query DB for FedConOfficeModel results using POST ZipID
$sql = "SELECT FedCon.FedConName, FedConOffice.FedConOfficeAddress, FedConOffice.FedConOfficeAddress2, Cities.City, Cities.ZipID, FedConOffice.Phone, ConDistricts.ConDistrict AS FedConDistrict, FedConOffice.Latitude, FedConOffice.Longitude
FROM ConDistricts JOIN FedCon ON ConDistricts.ConDistrict = FedCon.FedConDistrict
JOIN FedConOffice ON FedConOffice.FedConName = FedCon.FedConName
JOIN Cities ON Cities.ZipID = FedConOffice.ZipID
WHERE ConDistricts.ZipID = '$queryzip'";
$sqlresults = mysqli_query($conn, "SELECT FedCon.FedConName, FedConOffice.FedConOfficeAddress, FedConOffice.FedConOfficeAddress2, Cities.City, Cities.ZipID, FedConOffice.Phone, ConDistricts.ConDistrict AS FedConDistrict, FedConOffice.Latitude, FedConOffice.Longitude
FROM ConDistricts JOIN FedCon ON ConDistricts.ConDistrict = FedCon.FedConDistrict
JOIN FedConOffice ON FedConOffice.FedConName = FedCon.FedConName
JOIN Cities ON Cities.ZipID = FedConOffice.ZipID
WHERE ConDistricts.ZipID = '$queryzip'")
or die(mysqli_error($conn));
//Check if there are results
if ($result = mysqli_query($conn, $sql)){
//If so, then create a results array and a temporary one to hold the data
$resultArray = array();
$tempArray = array();
//Loop through each row in the result set
while($row = $result->fetch_object()){
//Add each row into our results array
$tempArray = $row;
array_push($resultArray, $tempArray);
}
//Finally, encode the array to JSON and output the results
echo json_encode($resultArray);
}
//Close connections
mysqli_close($conn);
?>
当我运行此脚本并通过POST传递有效的邮政编码时,输出如下所示:
[{"FedConName":"Adrian Smith","FedConOfficeAddress":"1811 West Second Street","FedConOfficeAddress2":"Suite 275","City":"Grand Island","ZipID":"68803","Phone":"(308) 384-3900","FedConDistrict":"NE-3","Latitude":"40.917091","Longitude":"-98.358109"},{"FedConName":"Adrian Smith","FedConOfficeAddress":"416 Valley View Drive","FedConOfficeAddress2":"Suite 600","City":"Scottsbluff","ZipID":"69361","Phone":"(308) 633-6333","FedConDistrict":"NE-3","Latitude":"41.878609","Longitude":"-103.656822"}]
这是在其中调用此脚本的Swift文件。
//
// FedConRetrieve.Swift
//
// Created by John Tree on 10/20/2018
// Copyright © 2018 John Tree. All rights reserved.
//
import UIKit
import Foundation
protocol FedConRetrieveProtocol: class{
func itemsDownloaded(items: NSArray)
}
class FedConRetrieve: NSObject, URLSessionDelegate {
//properties
//Declare a delegate property
weak var delegate: FedConRetrieveProtocol!
//Declare data variable to store incoming bits
var data = Data()
//Declare urlPath to phpservice
let urlPath: String = "http://localhost/~johntree/FedConOfficeQuery.php"
//Define function to retrieve data from MYSQL and handle it
func downloadItems(){
//Define function local variable to hold value from urlPath variable
let url: URL = URL(string: urlPath)!
//Instantiate a URLSession object, with a default configuration
let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.default)
//Assign a data task in the URLSession using the local url variable
let task = defaultSession.dataTask(with: url){(data, response, error)
in
//If there is an error, notify of failure
if error != nil{
print("Failed to download data")
}
//If there are no errors, notify success and parse JSON data
else{
print("Data downloaded")
self.parseJSON(_data: data!)
}
}
task.resume()
}
func parseJSON(_data: Data){
//Create an array variable to hold the data
var jsonResult = NSArray()
//Use JSON data to return a foundation object
do{
jsonResult = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as! NSArray
}
//If there is an error, print it to the console
catch let error as NSError{
print(error)
}
//Create an NSDictionary to hold key-value pairs
var jsonElement = NSDictionary()
//Create an array to hold each instance of the FedConOffice model
let offices = NSMutableArray()
//Loop through the JSON result Array to the last entry
for i in 0 ..< jsonResult.count{
//For each line in the JSON data, add it as a key-value pair to the dictionary
jsonElement = jsonResult[i] as! NSDictionary
//Instantiate a FedConOfficeModel object to hold the values from the DB
let office = FedConOfficeModel()
//Ensure none of the JsonElement values are nil, assign Dictionary entries to the variable names declared
if let FedConName = jsonElement["FedConName"] as? String,
let FedConOfficeAddress = jsonElement["FedConOfficeAddress"] as? String,
let FedConOfficeAddress2 = jsonElement["FedConOfficeAddress2"] as? String,
let City = jsonElement["City"] as? String,
let ZipID = jsonElement["ZipID"] as? String,
let Phone = jsonElement["Phone"] as? String,
let Latitude = jsonElement["Latitude"] as? String,
let Longitude = jsonElement["Longitude"] as? String
{
//Use the above variable names to assign values to the FedConOfficeModel object's properties
office.FedConName = FedConName
office.FedConOfficeAddress = FedConOfficeAddress
office.FedConOfficeAddress2 = FedConOfficeAddress2
office.City = City
office.ZipID = ZipID
office.Phone = Phone
office.Latitude = Latitude
office.Longitude = Longitude
}
//Add the fully populate FedConOfficeModel to the Array
offices.add(office)
print(offices.description)
}
//Pass the offices array to the protocol method for the view controller to use
DispatchQueue.main.async(execute: { () -> Void in self.delegate.itemsDownloaded(items: offices)
})
}
}
用作办公地点数据模型的Swift文件
//
// FedConOfficeModel.swift
// Gov4Me
//
// Created by John Tree on 10/20/18.
// Copyright © 2018 John Tree. All rights reserved.
//
import UIKit
class FedConOfficeModel: NSObject {
//properties
var FedConName: String?
var FedConOfficeAddress: String?
var FedConOfficeAddress2: String?
var City: String?
var ZipID: String?
var Phone: String?
var FedConDistrict: String?
var Latitude: String?
var Longitude: String?
//empty constructor
override init()
{
}
//construct with variable values
init(FedConName: String, FedConOfficeAddress: String, FedConOfficeAddress2: String, City: String, ZipID: String, Phone: String, FedConDistrict: String, Latitude: String, Longitude: String)
{
self.FedConName = FedConName
self.FedConOfficeAddress = FedConOfficeAddress
self.FedConOfficeAddress2 = FedConOfficeAddress2
self.City = City
self.ZipID = ZipID
self.Phone = Phone
self.FedConDistrict = FedConDistrict
self.Latitude = Latitude
self.Longitude = Longitude
}
//print objects current state
override var description: String
{
return "Name: \(String(describing: FedConName))," +
"Address: \(String(describing: FedConOfficeAddress))," +
"Address Line 2: \(String(describing: FedConOfficeAddress2))," +
"City: \(String(describing: City))," +
"Zip Code: \(String(describing: ZipID))," +
"Phone: \(String(describing: Phone))," +
"Congressional District: \(String(describing: FedConDistrict))," +
"Latitude: \(String(describing: Latitude))," +
"Longitude: \(String(describing: Longitude))"
}
}
还有从调用中接收数据的Swift文件。
//
// MyElectedOfficials.swift
// Gov4Me App
//
// Created by John Tree on 8/25/18.
// Copyright © 2018 John Tree. All rights reserved.
//
import UIKit
import CoreLocation
import Alamofire
class MyElectedOfficials: UIViewController, UITextFieldDelegate, CLLocationManagerDelegate
{
//Properties
//Variable to hold query URL selection from previous view
var queryURL = String()
//Outlet for textfield
@IBOutlet weak var ZipField: UITextField!
//Variable to hold user input
lazy var postZipID: String = ZipField.text!
//Variable to hold DB response in label
@IBOutlet weak var responseLabel: UILabel!
//Create a variable to contain the gradient layer data
var gradientLayer : CAGradientLayer!
//Set status bar to light text
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
//Outlet for submit button
@IBAction func Submit(_ sender: Any) {
let url = URL(string: queryURL)!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
let postString = "ZipID=" + postZipID
print(postString)
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
//check for fundamental networking error
print("error=\(String(describing: error))")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
//check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(String(describing: response))")
}
let responseString = String(data: data, encoding: .utf8)
print("responseString =" + responseString!)
self.responseLabel.text = responseString
}
task.resume()
performSegue(withIdentifier: "Officials1-Officials2", sender: self)
}
//Outlet for Back Button
@IBAction func backbuttontap(_ sender: Any) {
performSegue(withIdentifier: "Elected1-Pick", sender: self)
}
func createGradientLayer(){
gradientLayer = CAGradientLayer()
//Initialize gradienLayer object
gradientLayer.frame=self.view.bounds
//Set frame to view controller's bounds
gradientLayer.colors = [UIColor.green.cgColor, UIColor.cyan.cgColor]
//Create an array to hold the gradient colors
self.view.layer.insertSublayer(gradientLayer, at: 0)
//Add the gradient layer as a sublayer to the view
}
override func viewWillAppear(_ animated: Bool){
super.viewWillAppear(animated)
createGradientLayer()
//Before the view is added to the hierarchy, draw the gradient background
}
override func viewDidLoad(){
super.viewDidLoad()
ZipField.delegate = self
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning(){
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool{
textField.resignFirstResponder()
performSegue(withIdentifier: "Officials1-Officials2", sender: self)
return true
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
当我尝试运行此应用程序时,该应用程序不会崩溃,但是没有数据填充到我的应用程序中。我知道问题出在我的FedConRetrieve.Swift文件中的某个地方,但是我觉得上下文需要其他问题。当我一起尝试所有操作时,xcode控制台中的日志将提供以下输出。
2018-10-28 09:00:59.535344-0400 Gov4Me App[24587:13858262] libMobileGestalt MobileGestalt.c:890: MGIsDeviceOneOfType is not supported on this platform.
2018-10-28 09:01:03.641829-0400 Gov4Me App[24587:13858262] [MC] System group container for systemgroup.com.apple.configurationprofiles path is /Users/johntree/Library/Developer/CoreSimulator/Devices/D2A0C1BC-26A5-4C06-802B-71105AC6345F/data/Containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles
2018-10-28 09:01:03.726773-0400 Gov4Me App[24587:13858262] [MC] Reading from private effective user settings.
ZipID=68803
Data downloaded
Error Domain=NSCocoaErrorDomain Code=3840 "No value." UserInfo={NSDebugDescription=No value.}
responseString =[{"FedConName":"Adrian Smith","FedConOfficeAddress":"1811 West Second Street","FedConOfficeAddress2":"Suite 275","City":"Grand Island","ZipID":"68803","Phone":"(308) 384-3900","FedConDistrict":"NE-3","Latitude":"40.917091","Longitude":"-98.358109"},{"FedConName":"Adrian Smith","FedConOfficeAddress":"416 Valley View Drive","FedConOfficeAddress2":"Suite 600","City":"Scottsbluff","ZipID":"69361","Phone":"(308) 633-6333","FedConDistrict":"NE-3","Latitude":"41.878609","Longitude":"-103.656822"}]
=================================================================
Main Thread Checker: UI API called on a background thread: -[UILabel setText:]
PID: 24587, TID: 13858294, Thread name: (none), Queue name: NSOperationQueue 0x6000020fce20 (QOS: UNSPECIFIED), QoS: 0
Backtrace:
4 Gov4Me App 0x0000000106a33f78 $S10Gov4Me_App18MyElectedOfficialsC6SubmityyypFy10Foundation4DataVSg_So13NSURLResponseCSgs5Error_pSgtcfU_ + 2664
5 Gov4Me App 0x0000000106a3420d $S10Gov4Me_App18MyElectedOfficialsC6SubmityyypFy10Foundation4DataVSg_So13NSURLResponseCSgs5Error_pSgtcfU_TA + 13
6 Gov4Me App 0x0000000106a1f820 $S10Foundation4DataVSgSo13NSURLResponseCSgs5Error_pSgIegggg_So6NSDataCSgAGSo7NSErrorCSgIeyByyy_TR + 336
7 CFNetwork 0x0000000109784ef0 __75-[__NSURLSessionLocal taskForClass:request:uploadFile:bodyData:completion:]_block_invoke + 19
8 CFNetwork 0x000000010979b0bc __49-[__NSCFLocalSessionTask _task_onqueue_didFinish]_block_invoke + 172
9 Foundation 0x0000000106f8119d __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 7
10 Foundation 0x0000000106f810a4 -[NSBlockOperation main] + 68
11 Foundation 0x0000000106f7de13 -[__NSOperationInternal _start:] + 689
12 Foundation 0x0000000106f83e4a __NSOQSchedule_f + 227
13 libdispatch.dylib 0x000000010ac1e5d1 _dispatch_call_block_and_release + 12
14 libdispatch.dylib 0x000000010ac1f63e _dispatch_client_callout + 8
15 libdispatch.dylib 0x000000010ac22589 _dispatch_continuation_pop + 565
16 libdispatch.dylib 0x000000010ac21963 _dispatch_async_redirect_invoke + 859
17 libdispatch.dylib 0x000000010ac30028 _dispatch_root_queue_drain + 351
18 libdispatch.dylib 0x000000010ac309cd _dispatch_worker_thread2 + 130
19 libsystem_pthread.dylib 0x000000010b006169 _pthread_wqthread + 1387
20 libsystem_pthread.dylib 0x000000010b005be9 start_wqthread + 13
2018-10-28 09:01:06.956276-0400 Gov4Me App[24587:13858294] [reports] Main Thread Checker: UI API called on a background thread: -[UILabel setText:]
PID: 24587, TID: 13858294, Thread name: (none), Queue name: NSOperationQueue 0x6000020fce20 (QOS: UNSPECIFIED), QoS: 0
Backtrace:
4 Gov4Me App 0x0000000106a33f78 $S10Gov4Me_App18MyElectedOfficialsC6SubmityyypFy10Foundation4DataVSg_So13NSURLResponseCSgs5Error_pSgtcfU_ + 2664
5 Gov4Me App 0x0000000106a3420d $S10Gov4Me_App18MyElectedOfficialsC6SubmityyypFy10Foundation4DataVSg_So13NSURLResponseCSgs5Error_pSgtcfU_TA + 13
6 Gov4Me App 0x0000000106a1f820 $S10Foundation4DataVSgSo13NSURLResponseCSgs5Error_pSgIegggg_So6NSDataCSgAGSo7NSErrorCSgIeyByyy_TR + 336
7 CFNetwork 0x0000000109784ef0 __75-[__NSURLSessionLocal taskForClass:request:uploadFile:bodyData:completion:]_block_invoke + 19
8 CFNetwork 0x000000010979b0bc __49-[__NSCFLocalSessionTask _task_onqueue_didFinish]_block_invoke + 172
9 Foundation 0x0000000106f8119d __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 7
10 Foundation 0x0000000106f810a4 -[NSBlockOperation main] + 68
11 Foundation 0x0000000106f7de13 -[__NSOperationInternal _start:] + 689
12 Foundation 0x0000000106f83e4a __NSOQSchedule_f + 227
13 libdispatch.dylib 0x000000010ac1e5d1 _dispatch_call_block_and_release + 12
14 libdispatch.dylib 0x000000010ac1f63e _dispatch_client_callout + 8
15 libdispatch.dylib 0x000000010ac22589 _dispatch_continuation_pop + 565
16 libdispatch.dylib 0x000000010ac21963 _dispatch_async_redirect_invoke + 859
17 libdispatch.dylib 0x000000010ac30028 _dispatch_root_queue_drain + 351
18 libdispatch.dylib 0x000000010ac309cd _dispatch_worker_thread2 + 130
19 libsystem_pthread.dylib 0x000000010b006169 _pthread_wqthread + 1387
20 libsystem_pthread.dylib 0x000000010b005be9 start_wqthread + 13
您可以看到JSON响应字符串包含有效的格式化JSON数据,但从未将其添加到我的数据模型中,而且我无法弄清原因。一直试图解决这个问题两个星期都没有结果。如果有人可以提供任何见解,我将不胜感激。
我在这里尝试过的线程上找到了一种解决方案,但是它不起作用,将content-type标头值设置为使用JSON,
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
但是当我尝试这种方法时,响应字符串返回完全为空。