iOS Swift - Google Place API(Web)以奇怪格式返回JSON
我在Swift 3中构建iOS应用程序,并使用Google Places API获取地点数据。我正在使用iOS API来获取大部分我需要的数据。但我也需要获得iOS API尚未提供的开放时间。iOS Swift - Google Place API(Web)以奇怪格式返回JSON
所以我必须查询Web API来获取该信息。事情的请求方面工作正常,但是,一旦我得到结果,我把它变成JSON与JSONSerialisation
,然后在控制台中打印输出,这种JSON的格式很奇怪,我努力解析它。
当我把它粘贴到一个JSON阅读器时,它说它是无效的。
这里是一个看起来很奇怪,我与这些 “(” 和 “=” 的JSON:
["html_attributions": <__NSArray0 0x17001ccf0>(
)
, "result": {
"address_components" = (
{
"long_name" = 611;
"short_name" = 611;
types = (
"street_number"
);
},
{
"long_name" = "Post Street";
"short_name" = "Post St";
types = (
route
);
},
{
"long_name" = "Lower Nob Hill";
"short_name" = "Lower Nob Hill";
types = (
neighborhood,
political
);
},
{
"long_name" = "San Francisco";
"short_name" = SF;
types = (
locality,
political
);
},
{
"long_name" = "San Francisco County";
"short_name" = "San Francisco County";
types = (
"administrative_area_level_2",
political
);
},
{
"long_name" = California;
"short_name" = CA;
types = (
"administrative_area_level_1",
political
);
},
{
"long_name" = "United States";
"short_name" = US;
types = (
country,
political
);
},
{
"long_name" = 94109;
"short_name" = 94109;
types = (
"postal_code"
);
}
);
"adr_address" = "<span class=\"street-address\">611 Post St</span>, <span class=\"locality\">San Francisco</span>, <span class=\"region\">CA</span> <span class=\"postal-code\">94109</span>, <span class=\"country-name\">USA</span>";
"formatted_address" = "611 Post St, San Francisco, CA 94109, USA";
"formatted_phone_number" = "(415) 817-1391";
geometry = {
location = {
lat = "37.7877411";
lng = "-122.4120067";
};
viewport = {
northeast = {
lat = "37.78791149999999";
lng = "-122.4119977";
};
southwest = {
lat = "37.7876843";
lng = "-122.4120337";
};
};
};
icon = "https://maps.gstatic.com/mapfiles/place_api/icons/cafe-71.png";
id = 6a6d8b640d5260886eac5ce1b3aa73b3b0d0bb1c;
"international_phone_number" = "+1 415-817-1391";
name = "Joy's Place";
"opening_hours" = {
"open_now" = 1;
periods = (
{
close = {
day = 1;
time = 0000;
};
open = {
day = 0;
time = 0800;
};
},
{
close = {
day = 2;
time = 0000;
};
open = {
day = 1;
time = 0700;
};
},
{
close = {
day = 3;
time = 0000;
};
open = {
day = 2;
time = 0700;
};
},
{
close = {
day = 4;
time = 0000;
};
open = {
day = 3;
time = 0700;
};
},
{
close = {
day = 5;
time = 0000;
};
open = {
day = 4;
time = 0700;
};
},
{
close = {
day = 6;
time = 0000;
};
open = {
day = 5;
time = 0700;
};
},
{
close = {
day = 0;
time = 0000;
};
open = {
day = 6;
time = 0800;
};
}
);
"weekday_text" = (
"Monday: 7:00 am \U2013 12:00 am",
"Tuesday: 7:00 am \U2013 12:00 am",
"Wednesday: 7:00 am \U2013 12:00 am",
"Thursday: 7:00 am \U2013 12:00 am",
"Friday: 7:00 am \U2013 12:00 am",
"Saturday: 8:00 am \U2013 12:00 am",
"Sunday: 8:00 am \U2013 12:00 am"
);
};
photos = (
{
height = 3024;
"html_attributions" = (
"<a href=\"https://maps.google.com/maps/contrib/109383364523945736298/photos\">Kathleen S</a>"
);
"photo_reference" = "CoQBdwAAAFE8a_M5quVcX6frenilHEFVXTycrrhj5R3MoS5sd_vKG1Gj46aJVAvVl_a4HVcPS4G5Z2JS00Pugdegn4is9KSfwIw6IoMNBL1zo3hK2dQjfArUezH9wfSYpNJCNzi4bUO6EesC4bT74B1-hzM6Us4gzKpLLAfImaF3VTeRX-SGEhCLAqUUWZsgueYvTkx8mEi8GhRCDxXbJR-ddaQFwJizvZIKa4EYKA";
width = 4032;
},
{
height = 3024;
"html_attributions" = (
"<a href=\"https://maps.google.com/maps/contrib/109935156740971751576/photos\">Jake Lim</a>"
);
"photo_reference" = "CoQBdwAAANPkBrIvYxn3UrYliLvLgk3Z4tOmS_twOv9nbMSTFmAR00Mff8XCMWQRUeigOYw1dSheyerBgimteHAHdRMzTCAWkJ7V2yB0eBS5HBewcw2yKmGHrCuCxZDdBlovGzJrwhfo5cAUB0lFDIfAXfDGnNWifD8OmLdfEzsZt97peyIrEhC84xqRQnlK32XjZkXE5huQGhQiPI0EjQ284RkMqiYxwnoHVpXOMg";
width = 4032;
},
{
height = 2048;
"html_attributions" = (
"<a href=\"https://maps.google.com/maps/contrib/111937150500795140908/photos\">Hope Lynch</a>"
);
"photo_reference" = "CoQBdwAAAFMi1hIXlNKawhA7RPl9Oah4OS6ZZyNnBRpgkHtT5gCC0brwkl55azVyulgOLsYeBkz7lpDgrpW4_9A2vg6Dtcg1bf3vVYVb1PbvADXJAV8yNwmRu9xvfSaPlgl3ty7WKW2tl8Znv8pnTMtOxfYBiTqLuFpLiEdt03pmqQMtrTKSEhADBNOSal9jDonQAMac7ghIGhTkHYMlxquEKYBuKNlbJxYY2sMmxQ";
width = 1536;
},
{
height = 3024;
"html_attributions" = (
"<a href=\"https://maps.google.com/maps/contrib/100358998671099081635/photos\">\Uc784\Uc77c\Uc8fc</a>"
);
"photo_reference" = "CoQBdwAAAClp7S-w50auLq1Rtet0Glz5UjwWmSFGWKsceURE2ydHve0hFYZqf-OewYNm7xqRBA_Vdtl-nNSIgHawN5JCfyXW48fMRFi7L1mYiycxPjpZSwcH8VlQUisS1dEURkbSaY7lBH1niz197x0hhK0eTIdaPjsXboXcij7xQm6bsYSYEhDt416My2DDwuNUg7MWDrzDGhTIxwfK1eBLCjzto2X_10Ed9pvsyQ";
width = 4032;
},
{
height = 5312;
"html_attributions" = (
"<a href=\"https://maps.google.com/maps/contrib/113957702965980710581/photos\">Tim Lee</a>"
);
"photo_reference" = "CoQBdwAAANNU12JQOxIa6Y4MBHzNedo42kZmStvSbw_JF-lhdCOtj7QoiuwfWvj1MjECq29AO7CM3QFeJiQQn3cV3GWilWHoI0EDXBodlGRe3MAG6tNhBnKBYB_jNuM_muu2o1ngWmsOXP6cmcuZmxK1z5w5cDX_aUrpli4vkKRkNuqIdbc_EhACCVmjsS6GxgLanF9s9KrVGhSEL_DpaNArYwocJzkX688WFLsEUQ";
width = 2988;
},
{
height = 3024;
"html_attributions" = (
"<a href=\"https://maps.google.com/maps/contrib/109383364523945736298/photos\">Kathleen S</a>"
);
"photo_reference" = "CoQBdwAAAK8OjkKwRH84A_OKMhCXVemX8vxLS8nCp7c30JOvt7SiqGL5_XQCKz03ZiH-Tq2sshn_UBKttz3oyDJIhfAT2VTuDZgnbAPCSlNQUoP80yeATWPJJFcjJ4XxsKcQHF6Y5IDFzszEIAJYhMBQJ9I6RKMaBGMlRftIZeAEkFhN5AEtEhAozH6UEf-m0XthHPES1ldPGhTB3-JgPzRJ8aDX-B5_SyW2vs4E8Q";
width = 4032;
},
{
height = 3024;
"html_attributions" = (
"<a href=\"https://maps.google.com/maps/contrib/114832380918896847951/photos\">Deby Lepage</a>"
);
"photo_reference" = "CoQBdwAAAJyut1B1yUQD6mq1FD8gQVNKo16sS6-xbnGeSs8jDtb3C5oF_oUcoUGpLTnQpHqxHfsFh7oL7cBud_h-h0xc2fhNuIkMBFQEWeZhCrmoqph5U79sH98jtOKJgjxs6i0W3-cyDlyURIux8oBfB3QzNhLqeHapJ_WFAMai74Z5ufo1EhDlCT1tkYirOAlgg18i1MVEGhQ_StyBaN3neLaiKNN2s-cTFEPz1w";
width = 4032;
},
{
height = 3024;
"html_attributions" = (
"<a href=\"https://maps.google.com/maps/contrib/114832380918896847951/photos\">Deby Lepage</a>"
);
"photo_reference" = "CoQBdwAAAJ-OEm5p7FZZFsPIUBBlB-v5uPhGz3K_j9qD4fIF7lUTFUW3I_-O9gy_MZCUkD5XlZJXa2F9kfZ4Ru-Eb989IYc6YQzc3i_N3ozUOyuPhL2FDUqqkl-pltfNJJBoSOlDp4M4Ay9yrKQP6BpUP8i9P9L0gDgv-ycKDIWNh-vUDmtwEhA6F3RmxZ_tsbE131S_RcYoGhTOQTkUt1Zm9b8qUD7yxiWTjemxxQ";
width = 4032;
},
{
height = 3024;
"html_attributions" = (
"<a href=\"https://maps.google.com/maps/contrib/109383364523945736298/photos\">Kathleen S</a>"
);
"photo_reference" = "CoQBdwAAANkAGV7dv_jVNv_mGmJ9ilcPKJ9Vx24Fs1MEwy0Ce6B6hoGZ-8I0pbFVjS99TicGo3zGdi6eUbpEm76C5XplnnkuM4HGWLN1PkzHk98vVeY4hJRGY1o2qnoLaf6DnvPBmhpbrucCJK9WCNRH3-q1UZ6lzFwgxEwFAxbf-KSwJRqkEhD2Si7TWKZNQcb7bXy29QaVGhR7Yk3dOMasHvsoNwa9y-FMxzNV4w";
width = 4032;
},
{
height = 3024;
"html_attributions" = (
"<a href=\"https://maps.google.com/maps/contrib/114832380918896847951/photos\">Deby Lepage</a>"
);
"photo_reference" = "CoQBdwAAABqKoM9Is_KWHUlzFyDIAOh41GwUaOqPC5EwWqB_uwDTRsB4XbOksl4qylHlSbTuXpRrUUaAETi-I0coY8KyLtS5E6NxcM4f93iMl6kgsb8apJRGziedKV99EUNcdeaTWmWJOuxirP_7wwiadwUiwbmfjZ05e2EkAtfmjCb8vHTYEhDsAfUeyhcyQu_riR-Vrd9JGhRwlTegpWWdYn9uVGVhs02SjIyXsQ";
width = 4032;
}
);
"place_id" = "ChIJheCrEY6AhYARxCkT8_KjDWE";
rating = "4.4";
reference = "CmRRAAAAeYm_xV5gsn_eVlrvpkEolaqaHFO0CWS5rWXJ5z5QWX8ReJKLPl6eDnvFM0PD2BNMkgfui9Z42_jmUxCIeTeZi3OEaod73XuU_rzLpRAdlOm8IcTaLX6YeYJeS4qFqZxLEhBUzZmWo-SU9WY4YG8WP8GOGhSwAPbhHWRuZh0X6wC1LMD3Los44A";
reviews = (
{
aspects = (
{
rating = 2;
type = overall;
}
);
"author_name" = "Lanxin Chu";
"author_url" = "https://www.google.com/maps/contrib/117750042826931398790/reviews";
language = en;
rating = 4;
"relative_time_description" = "5 months ago";
text = "Red bean shaved ice was good and definitely did not skimp out on ingredients! Green tea latte was solid. Ambiance was pretty nice. There were a lot of people studying there; as noted by others this makes for somewhat limited seating sometimes so keep that in mind.";
time = 1470610849;
},
{
aspects = (
{
rating = 3;
type = overall;
}
);
"author_name" = "Esther Gibbs";
"author_url" = "https://www.google.com/maps/contrib/110692487628239988503/reviews";
language = en;
rating = 5;
"relative_time_description" = "a month ago";
text = "Delicious food and drink- especially their sweet potato latte! Fairtrade and organic everything and a lovely working environment";
time = 1479462640;
},
{
aspects = (
{
rating = 2;
type = overall;
}
);
"author_name" = "Johnny Wang";
"author_url" = "https://www.google.com/maps/contrib/103379264202553362035/reviews";
language = en;
"profile_photo_url" = "//lh6.googleusercontent.com/-EtpIyKVUteI/AAAAAAAAAAI/AAAAAAAAA4c/riPrz4_6j-s/photo.jpg";
rating = 4;
"relative_time_description" = "7 months ago";
text = "It's been called to my attention that I never reviewed this place, despite the number of times I've visited, which is... surprising. Honestly though, there's not too much to say: I've only ever come here for the patbingsoo, which is massively generous in portion size, and fantastically delicious in flavor, and definitely ideal for sharing. But hey, everything can be a personal serving if you try hard enough.\n\nAs for the place itself, it's a nice, chill little cafe that's been packed every single time I go, so seating can be a little hard to find at times. You'll usually find it occupied by folks busy working away on their laptops.\n\n***Accessibility Info***\n\nVenue - On the smaller side, as far as cafes/coffee shops go, with about 2/3 of the seating being accessible: those along the walls were bench seating, and there's lower coffee table seating towards the right as well, leaving only the middle aisle and outer seats along the sides accessible.\n\nBathroom - Didn't try them.";
time = 1465162538;
},
{
aspects = (
{
rating = 2;
type = overall;
}
);
"author_name" = "Victor Vu";
"author_url" = "https://www.google.com/maps/contrib/108347888656400683025/reviews";
language = en;
"profile_photo_url" = "//lh4.googleusercontent.com/-92ZhOOjfwfE/AAAAAAAAAAI/AAAAAAAAZqA/16j_bEwt6fk/photo.jpg";
rating = 4;
"relative_time_description" = "7 months ago";
text = "Great place to study... when it's quiet. There's enough light to clearly see your paperwork. Music is on the medium side and easy to phase out when you put on headphones, or focus really hard. It's really chill!\n\nFood and drinks are nice. It's a great place for coffee and deserts. Most people get waffles or ice cream here. Their matcha green tea is nice as well.\n\nThe only problem is that there is never enough seating during peak hours and it gets claustrophobic when it's crowded with people doing their homework.\n\nSeats are also cheap and hurt your butt.\n\nThis place usually attracts the Asian crowd.";
time = 1463551785;
},
{
aspects = (
{
rating = 1;
type = overall;
}
);
"author_name" = "Brian Melton";
"author_url" = "https://www.google.com/maps/contrib/103909645378067844462/reviews";
language = en;
"profile_photo_url" = "//lh4.googleusercontent.com/-enGmeXKqYC0/AAAAAAAAAAI/AAAAAAAA4eo/maQQGZ8Etdo/photo.jpg";
rating = 3;
"relative_time_description" = "a month ago";
text = "Expensive, small-sized coffees make this coffee shop feel like poor value-for-money. Limited food options but has great desserts: try the macaroons.";
time = 1480554027;
}
);
scope = GOOGLE;
types = (
cafe,
restaurant,
food,
store,
"point_of_interest",
establishment
);
url = "https://maps.google.com/?cid=6993426060231780804";
"utc_offset" = "-480";
vicinity = "611 Post Street, San Francisco";
website = "http://www.joysplacecafe.com/";
}, "status": OK]
这里是我的代码与虚拟查询:
let url = URL(string: "https://maps.googleapis.com/maps/api/place/details/json?placeid=ChIJheCrEY6AhYARxCkT8_KjDWE&key=[MYAPIKEY]")
let urlRequest = URLRequest(url: url!)
let task = URLSession.shared.dataTask(with: urlRequest) {
(data, response, error) in
guard error == nil else {
print(error!)
return
}
guard let responseData = data else {
print("Error: did not receive data")
return
}
do {
guard let placeData = try JSONSerialization.jsonObject(with: responseData, options: JSONSerialization.ReadingOptions.allowFragments)
as? [String: Any] else {
print("error trying to convert data to JSON")
return
}
print("The placeData is: \(placeData.description)")
guard let website = placeData["website"] as? String else {
print("Could not get the website from JSON")
return
}
print("The title is: \(website)")
} catch {
print("error trying to convert data to JSON")
return
}
}
task.resume()
任何帮助了解正在发生的事情都将不胜感激。最终目标是让开放时间成为词典,其中关键是一周的日子,值是开放时间。
在此先感谢
的问题是,reponseData
是用钥匙response
字典包含要实际的字典。该JSON看起来像:
{
"result": {
"website": "example.com"
}
}
所以正确的代码是:
let url = URL(string: "https://maps.googleapis.com/maps/api/place/details/json?placeid=ChIJheCrEY6AhYARxCkT8_KjDWE&key=[MYAPIKEY]")
let urlRequest = URLRequest(url: url!)
let task = URLSession.shared.dataTask(with: urlRequest) {
(data, response, error) in
guard error == nil else {
print(error!)
return
}
guard let responseData = data else {
print("Error: did not receive data")
return
}
do {
guard let placeData = try JSONSerialization.jsonObject(with: responseData, options: JSONSerialization.ReadingOptions.allowFragments)
as? [String: Any] else {
print("error trying to convert data to JSON")
return
}
print("The placeData is: \(placeData.description)")
guard let website = (placeData["result"] as? [String : Any])?["website"] as? String else {
print("Could not get the website from JSON")
return
}
print("The title is: \(website)")
} catch {
print("error trying to convert data to JSON")
return
}
}
task.resume()
我只是改变:
guard let website = placeData["website"] as? String else {
到:
guard let website = (placeData["result"] as? [String : Any])?["website"] as? String else {
谢谢Coder256!有点混乱,因为这是我第一次这样做。我已经尝试了你的代码示例,并且我得到了我想要的。 –
谢谢埃里克,看起来我确实感到困惑。将研究这一点。我是新来的;) –