Memo

メモ > 技術 > 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() } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { 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() } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { 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) } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { 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) } } struct ContentView_Previews: PreviewProvider { static var previews: some View { 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() } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { 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>

Advertisement