質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.44%
Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

559閲覧

[Swift] delegateがnilになってしまう

AdamYoneda

総合スコア10

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2022/06/18 05:39

編集2022/06/18 08:43

実現したいこと

swift初学者です。delegateについて自力で解決できないところがあり、ご回答いただけますとありがたいです。

位置情報を元に天気に関する情報をAPIから取得し、その内容を表示するアプリを作成しています。
APIから取得したデータをdelegateを用いて、WeatherManagerクラスからWeatherViewControllerクラスにWeatherModelオブジェクトを渡して処理を実行しようとしています。

現在の問題

WeatherManagerのdelegateがnilになったままで、処理が実行されません。

環境

Xcode(ver 13.3.1)
macOS Monterey(ver12.3.1)

該当のコード

swift

1import Foundation 2 3// delegate design parttern 4protocol WeatherManagerDelegate:AnyObject { 5 func didUpdateWeather(inputWeatherModel: WeatherModel) 6} 7 8class WeatherManager { 9 10 // delegate 11 weak var delegate: WeatherManagerDelegate? 12 13 // fetchCoordinate 14 func fetchWeather(urlString: String) { 15 performRequest(inputURLString: urlString) 16 } 17 18 // performRequest 19 func performRequest(inputURLString: String) { 20 // 1. Create URL 21 if let url = URL(string: inputURLString) { 22 // 2. Create URLSession 23 let session = URLSession(configuration: .default) 24 // 3. Give the URLSession a task 25 let task = session.dataTask(with: url) { (data, response, error) in 26 if error != nil { 27 print(error!) 28 return 29 } 30 if let safeData = data { 31 if let weather = self.parseJSON(JSONobject: safeData) { 32 // ---------- 問題の箇所 ---------- 33 self.delegate?.didUpdateWeather(inputWeatherModel: weather) 34 } 35 } 36 } 37 // 4. Start the task 38 task.resume() 39 } 40 } 41 42 // parse JSON object 43 func parseJSON(JSONobject: Data) -> WeatherModel? { 44 let decoder = JSONDecoder() 45 do { 46 let decodedData = try decoder.decode(WeatherData.self, from: JSONobject) 47 48 let id = decodedData.weather[0].id 49 let temp = decodedData.main.temp 50 let name = decodedData.name 51 52 let weather = WeatherModel(conditionId: id, cityName: name, temperature: temp) 53 return weather 54 55 } catch { 56 print(error) 57 return nil 58 } 59 } 60 61}

swift

1import UIKit 2 3class WeatherViewController: UIViewController, UITextFieldDelegate, WeatherManagerDelegate { 4 5 @IBOutlet weak var conditionImageView: UIImageView! 6 @IBOutlet weak var temperatureLabel: UILabel! 7 @IBOutlet weak var searchTextField: UITextField! 8 @IBOutlet weak var cityLabel: UILabel! 9 10 var weatherManager = WeatherManager() 11 var coordinateManager = CoordinateManager() 12 13 override func viewDidLoad() { 14 super.viewDidLoad() 15 // Do any additional setup after loading the view. 16 searchTextField.delegate = self 17 searchTextField.keyboardType = .asciiCapable 18 weatherManager.delegate = self 19 } 20 21 @IBAction func searchPressed(_ sender: UIButton) { 22 searchTextField.endEditing(true) 23 } 24 25 func textFieldShouldReturn(_ textField: UITextField) -> Bool { 26 searchTextField.endEditing(true) 27 return true 28 } 29 30 func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { 31 if textField.text != "" { 32 return true 33 } else { 34 textField.placeholder = "Type Something" 35 return false 36 } 37 } 38 39 func textFieldDidEndEditing(_ textField: UITextField) { 40 41 if let city = searchTextField.text { 42 coordinateManager.fetchCoordinate(cityName: city) 43 } 44 searchTextField.text = "" 45 } 46 // ---------- プロトコルのメソッド ---------- 47 func didUpdateWeather(inputWeatherModel: WeatherModel) { 48 print(inputWeatherModel.temperature) 49 } 50}

swift

1import Foundation 2 3struct WeatherModel { 4 let conditionId: Int 5 let cityName: String 6 let temperature: Double 7}

swift

1 2import Foundation 3 4struct CoordinateManager { 5 6 // WeatherManager 7 let weathetManager = WeatherManager() 8 // geographical coordinates(lat, lon) 地理座標 9 let coordinateURL = "https://api.openweathermap.org/geo/1.0/direct?limit=1&appid=c8e60c6317c653a1789294c00f54ae19" 10 11 // fetchCoordinate 12 func fetchCoordinate(cityName: String) { 13 let urlString = "\(coordinateURL)&q=\(cityName)" 14 performRequest(inputURLString: urlString) 15 } 16 17 // transformURLString 18 func transformURLString(_ string: String) -> URLComponents? { 19 guard let urlPath = string.components(separatedBy: "?").first else { 20 return nil 21 } 22 var components = URLComponents(string: urlPath) 23 if let queryString = string.components(separatedBy: "?").last { 24 components?.queryItems = [] 25 let queryItems = queryString.components(separatedBy: "&") 26 for queryItem in queryItems { 27 guard let itemName = queryItem.components(separatedBy: "=").first, 28 let itemValue = queryItem.components(separatedBy: "=").last else { 29 continue 30 } 31 components?.queryItems?.append(URLQueryItem(name: itemName, value: itemValue)) 32 } 33 } 34 return components! 35 } 36 37 // performRequest 38 func performRequest(inputURLString: String) { 39 // 1. Create URL 40 let components = transformURLString(inputURLString) 41 if let url = components?.url { 42 // 2. Create URLSession 43 let session = URLSession(configuration: .default) 44 // 3. Give the URLSession a task 45 let task = session.dataTask(with: url) {(data, response, error) in 46 if error != nil { 47 print(error!) 48 return 49 } 50 if let safeData = data { 51 self.parseJSON(JSONobject: safeData) 52 } 53 } 54 // 4. Start the task 55 task.resume() 56 } 57 } 58 59 // parseJSON 60 func parseJSON(JSONobject: Data) { 61 let decoder = JSONDecoder() 62 do { 63 let decodedData = try decoder.decode([CoordinateData].self, from: JSONobject) 64 let name = decodedData[0].name 65 let lat = decodedData[0].lat 66 let lon = decodedData[0].lon 67 68 let coordinateModel = CoordinateModel(name: name, lat: lat, lon: lon) 69 let weatherURL = coordinateModel.urlString 70 71 // ------- WeatherManager fetchWeather --------- 72 weathetManager.fetchWeather(urlString: weatherURL) 73 } catch { 74 print(error) 75 } 76 } 77} 78

swift

1import Foundation 2 3struct CoordinateModel { 4 let name: String 5 let lat: Double 6 let lon: Double 7 8 // wheather 地理座標を元に検索した天気の情報 9 let weatherstr = "https://api.openweathermap.org/data/2.5/weather?" 10 let str = "units=metric&appid=c8e60c6317c653a1789294c00f54ae19#" 11 12 // computedproperty 13 var urlString: String { 14 return "\(weatherstr)&lat=\(lat)&lon=\(lon)&\(str)" 15 } 16}

よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hoshi-takanori

2022/06/18 08:34

fetchWeather はどこで呼んでますか?
AdamYoneda

2022/06/18 08:41

失礼しました。 追加したコードのstruct CoordinateManager内の下の方で呼んでいます。 CoordinateManager内では先に都市名から地理座標を得るAPIを利用して、天気の情報を得るURLを作成しています。
guest

回答1

0

自己解決

stackoverflowでも質問したところ、
WeatherManagerの2つのインスタンスを書いており、そのためWeatherVC内のWeatherManager()が使われずにいたためnilのままでした。

解決策としてはCoordinateManagerの内容をWeatherManager内に持ってきて、WeatherManagerのインスタンスをWeatherVC内のみにすると機能しました。

検討いただいた方々ありがとうございました!

投稿2022/06/18 10:05

AdamYoneda

総合スコア10

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.44%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問