メモ > 技術 > IDE: Xcode > SwiftUI+ネットワーク
SwiftUI+ネットワーク
■JSONを取得して表示する
【Swift】URLSessionまとめ - Qiita
https://qiita.com/shiz/items/09523baf7d1cd37f6dee
ContentView.swift
import SwiftUI
struct ContentView: View {
@State private var result = "Now Loading..."
var body: some View {
Text(result)
.padding()
.onAppear {
let target = URL(string: "https://refirio.org/memos/ios/json_test.php")!
let task = URLSession.shared.dataTask(with: target) { data, response, error in
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
guard let status = (json as AnyObject).object(forKey: "status") else {
throw NSError(domain: "ステータスを取得できません", code: -1, userInfo: nil)
}
guard let message = (json as AnyObject).object(forKey: "message") else {
throw NSError(domain: "メッセージを取得できません", code: -1, userInfo: nil)
}
print(status)
print(message)
if let status = status as? String {
if (status != "OK") {
result = "不正なステータスです"
throw NSError(domain: result, code: -1, userInfo: nil)
}
}
if let message = message as? String {
result = message
}
} catch {
print(error.localizedDescription)
}
}
}
task.resume()
}
}
}
#Preview {
ContentView()
}
json_test.php の内容は以下のとおり
<?php
$data = array(
'status' => 'OK',
'message' => '完了しました。',
);
echo json_encode($data);
exit;
■JSONを取得して一覧に表示する
【SwiftUI】ForEachの使い方(2/2) | カピ通信
https://capibara1969.com/1650/
ContentView.swift
import SwiftUI
struct Book: Identifiable {
var id = UUID()
var title: String
var price: Int
}
struct ContentView: View {
@State private var books: [Book] = []
var body: some View {
List {
ForEach(books) { book in
HStack {
Text(book.title)
Spacer()
Text(String(book.price) + "円")
}
}
}.onAppear {
let target = URL(string: "https://refirio.org/memos/ios/json_book.php")!
let task = URLSession.shared.dataTask(with: target) { data, response, error in
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
if let items = (json as AnyObject).object(forKey: "books") {
for item in items as! NSArray {
guard let titleObject = (item as AnyObject).object(forKey: "title") else {
continue
}
guard let priceObject = (item as AnyObject).object(forKey: "price") else {
continue
}
guard let title = titleObject as? String else {
continue
}
guard let price = priceObject as? String else {
continue
}
print(title)
print(price)
books.append(Book(title: title, price: Int(price)!))
}
}
} catch {
print(error.localizedDescription)
}
}
}
task.resume()
}
}
}
#Preview {
ContentView()
}
json_book.php の内容は以下のとおり
<?php
$data = array(
'books' => array(
array(
'title' => 'C言語入門',
'price' => '1500'
),
array(
'title' => 'JAVA言語入門',
'price' => '1600'
),
array(
'title' => 'Ruby言語入門',
'price' => '2000'
)
)
);
echo json_encode($data);
exit;
■インターネット上の画像を表示
SwiftUIで非同期で画像を表示する方法 - Qiita
https://qiita.com/From_F/items/e3eb8bd279f75b864865
ImageDownloader.swift
import Foundation
class ImageDownloader : ObservableObject {
@Published var downloadData: Data? = nil
func downloadImage(url: String) {
guard let imageURL = URL(string: url) else { return }
DispatchQueue.global().async {
let data = try? Data(contentsOf: imageURL)
DispatchQueue.main.async {
self.downloadData = data
}
}
}
}
URLImage.swift
import SwiftUI
struct URLImage: View {
let url: String
@ObservedObject private var imageDownloader = ImageDownloader()
init(url: String) {
self.url = url
self.imageDownloader.downloadImage(url: self.url)
}
var body: some View {
if let imageData = self.imageDownloader.downloadData {
return Image(uiImage: UIImage(data: imageData)!).resizable()
} else {
return Image(uiImage: UIImage(systemName: "icloud.and.arrow.down")!).resizable()
}
}
}
ContentView.swift
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
URLImage(url: "https://1.bp.blogspot.com/-_CVATibRMZQ/XQjt4fzUmjI/AAAAAAABTNY/nprVPKTfsHcihF4py1KrLfIqioNc_c41gCLcBGAs/s400/animal_chara_smartphone_penguin.png")
.aspectRatio(contentMode: .fit)
}
}
}
#Preview {
ContentView()
}
■RSSリーダー
ImageDownloader.swift と URLImage.swift が必要
内容は「インターネット上の画像を表示」を参照
ContentView.swift
import SwiftUI
struct Article: Identifiable {
var id = UUID()
var title: String
var url: String
var image: String
var datetime: String
var name: String
}
struct ContentView: View {
@State private var articles: [Article] = []
var body: some View {
List {
ForEach(articles) { article in
Link(destination: URL(string: article.url)!, label: {
VStack {
Text(article.title).font(.title).frame(maxWidth: .infinity, alignment: .leading).lineLimit(1).truncationMode(.tail)
Text("by " + article.name + " at " + article.datetime).frame(maxWidth: .infinity, alignment: .leading).lineLimit(1).truncationMode(.middle)
if article.image != "" {
URLImage(url: article.image).aspectRatio(contentMode: .fit)
}
}
})
}
}.onAppear {
getData()
}
}
/*
* JSONデータを取得
*/
func getData() {
let target = URL(string: "https://refirio.org/reader/?type=json")!
let task = URLSession.shared.dataTask(with: target) { data, response, error in
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
if let items = (json as AnyObject).object(forKey: "articles") {
for item in items as! NSArray {
guard let titleObject = (item as AnyObject).object(forKey: "title") else {
continue
}
guard let urlObject = (item as AnyObject).object(forKey: "url") else {
continue
}
guard let imageObject = (item as AnyObject).object(forKey: "image") else {
continue
}
guard let datetimeObject = (item as AnyObject).object(forKey: "datetime") else {
continue
}
guard let nameObject = (item as AnyObject).object(forKey: "name") else {
continue
}
guard let title = titleObject as? String else {
continue
}
guard let url = urlObject as? String else {
continue
}
/*
guard let image = imageObject as? String else {
continue
}
*/
guard let datetime = datetimeObject as? String else {
continue
}
guard let name = nameObject as? String else {
continue
}
var image:String
if imageObject is NSNull {
image = ""
} else {
image = imageObject as! String
}
print(title)
print(url)
print(image)
print(datetime)
print(name)
articles.append(
Article(
title: title,
url: url,
image: image,
datetime: convertDateFormat(datetime: datetime),
name: name
)
)
}
}
} catch {
print(error.localizedDescription)
}
}
}
task.resume()
}
/*
* 日時をフォーマットして返す
*/
func convertDateFormat(datetime:String) -> String {
// 引数で渡ってきた文字列をDateFormatterでDateにする
let inFormatter = DateFormatter()
inFormatter.dateFormat = "yyyy/MM/dd HH:mm:ss"
let date:Date = inFormatter.date(from: datetime)! as Date
// Dateから指定のフォーマットの文字列に変換する
let outFormatter = DateFormatter()
outFormatter.dateFormat = "MM/dd HH:mm"
return outFormatter.string(from: date as Date)
}
}
#Preview {
ContentView()
}
■データをPOSTする
URLsessionを用いたHTTPリクエストの方法(Swift, Xcode) - Qiita
https://qiita.com/shungo_m/items/64564fd822a7558ac7b1
HTTP GETとPOST(Swift) [URLRequest, URLSession] iOS Objective-C, Swift Tips-モバイル開発系(K)
http://www.office-matsunaga.biz/ios/description.php?id=54
Swift で日本語を含む URL を扱う - Qiita
https://qiita.com/yum_fishing/items/db029c097197e6b27fba
ContentView.swift
import SwiftUI
struct ContentView: View {
@State private var title = ""
@State private var text = ""
var body: some View {
VStack {
Text("データを編集します。")
.padding(10)
TextField("タイトル", text: $title)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding(10)
TextEditor(text: $text)
.frame(width: UIScreen.main.bounds.width * 0.95, height: 200)
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(Color(red: 0.9, green: 0.9, blue: 0.9), lineWidth: 1)
)
Button(action: {
let titleValue = String(title).addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? ""
let textValue = String(text).addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? ""
let url = URL(string: "https://refirio.org/memos/ios/request/post.php")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = String("title=" + titleValue + "&text=" + textValue).data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data else { return }
do {
let object = try JSONSerialization.jsonObject(with: data, options: [])
print(object)
} catch let error {
print(error)
}
}
task.resume()
}) {
Text("保存")
}.padding(10)
}
.onAppear {
let target = URL(string: "https://refirio.org/memos/ios/request/get.php")!
let task = URLSession.shared.dataTask(with: target) { data, response, error in
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
guard let statusData = (json as AnyObject).object(forKey: "status") else {
throw NSError(domain: "ステータスを取得できません", code: -1, userInfo: nil)
}
guard let titleData = (json as AnyObject).object(forKey: "title") else {
throw NSError(domain: "タイトルを取得できません", code: -1, userInfo: nil)
}
guard let textData = (json as AnyObject).object(forKey: "text") else {
throw NSError(domain: "テキストを取得できません", code: -1, userInfo: nil)
}
print(statusData)
print(titleData)
print(textData)
let result: String
if let status = statusData as? String {
if (status != "OK") {
result = "不正なステータスです"
throw NSError(domain: result, code: -1, userInfo: nil)
}
}
if let titleString = titleData as? String {
title = titleString
}
if let textString = textData as? String {
text = textString
}
} catch {
print(error.localizedDescription)
}
}
}
task.resume()
}
}
}
#Preview {
ContentView()
}
各サーバサイドプログラムの内容は以下のとおり(index.php は動作確認用)
get.php
<?php
// データを取得
$result = file_get_contents('./data.txt');
if ($result === false) {
$result = json_encode(array(
'status' => 'NG',
));
}
list($title, $text) = explode("\n", $result);
$title = str_replace('\n', "\n", $title);
$text = str_replace('\n', "\n", $text);
$result = array(
'status' => 'OK',
'title' => $title,
'text' => $text,
);
// 結果を返す
echo json_encode($result);
post.php
<?php
// データを取得
$title = str_replace(array("\r\n","\n","\r"), '\n', $_POST['title']);
$text = str_replace(array("\r\n","\n","\r"), '\n', $_POST['text']);
// データを保存
if (file_put_contents('./data.txt', $title . "\n" . $text) === false) {
$result = array(
'status' => 'NG',
);
} else {
$result = array(
'status' => 'OK',
);
}
// 結果を返す
echo json_encode($result);
index.php
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$result = file_get_contents(
'http://localhost/~refirio_org/memos/ios/request/post.php',
false,
stream_context_create(
array(
'http' => array(
'method' => 'POST',
'header' => 'Content-Type: application/x-www-form-urlencoded',
'content' => http_build_query(
array(
'title' => $_POST['title'],
'text' => $_POST['text'],
)
)
)
)
)
);
if ($result === false) {
exit('NG');
} else {
exit('OK');
}
} else {
$result = file_get_contents('http://localhost/~refirio_org/memos/ios/request/get.php');
if ($result === false) {
$result = '';
}
$json = json_decode($result, true);
if (empty($json) || $json['status'] !== 'OK') {
$json['title'] = 'タイトル';
$json['text'] = 'テキスト';
}
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Request</title>
</head>
<body>
<h1>Request</h1>
<form action="index.php" method="post">
<fieldset>
<legend>送信フォーム</legend>
<dl>
<dt>タイトル</dt>
<dd><input type="text" name="title" size="30" value="<?php echo htmlspecialchars($json['title'], ENT_QUOTES) ?>"></dd>
<dt>テキスト</dt>
<dd><textarea name="text" rows="10" cols="50"><?php echo htmlspecialchars($json['text'], ENT_QUOTES) ?></textarea></dd>
</dl>
<p><input type="submit" value="送信する"></p>
</fieldset>
</form>
</html>