0

I am new to SwiftUI and developing, and trying to make a drug searching app I am in the process of making a search text field, that shows a list of drug name suggestions

This is the array of data and the text field inside a struct.

@State var drugNameSearch = [DrugNameSearch]()

TextField("Insert Drug Name" , text: $drugName, onEditingChanged: { isEdited in
                      self.isEdited = isEdited
                      self.isDrugSearched = isEdited
                      
              })
                  .frame(height:geometry.size.height/35)
                  .onChange(of: drugName, perform: { value in
                      self.fetchData()
                  })
              
              if isDrugSearched == true {                    
                  ForEach(drugNameSearch.filter({drugName.isEmpty ? false : $0.name.contains(drugName) }), id: \.self) { item in
                  HStack{
                      HStack{
                       Image(systemName: "magnifyingglass")
                       Text(item.name)
                      }
                      .onTapGesture{self.drugName = item.name}
                    Spacer()
                  }
                }
                  
              }
              else{}

And below is the method with the problem. Without the "&item_name=(drugName)", the app launches fine but works with limited data fetched. With the code below, the app crashes with the URL unwrapping issue. Please give me advice...

 private func fetchData() {
   
    print("Drug Name Search Attempted!")

       let url = URL(string: "http://apis.data.go.kr/1471000/DrugPrdtPrmsnInfoService/getDrugPrdtPrmsnDtlInq?serviceKey=SERVICEKEY&item_name=\(drugName)&numOfRows=10&type=json")  
    
    URLSession.shared.dataTask(with: url!){(data, response, error) in
        do {
            if let drugNameData = data {
              let decodedData = try JSONDecoder().decode(DrugFetch.self, from: drugNameData)
                DispatchQueue.main.async {
                        self.drugNameSearch = decodedData.body.items
                }
            } else {
                print("No Data for drugNameSearch")
            }
        }
        catch {
            print("drugNameSearch Fetching Error: \(error)")
        }
        
    }//URLSession
    .resume()
    
}
Muhammad Mohsin Khan
  • 1,444
  • 7
  • 16
  • 23
WTH_MD
  • 15
  • 3

2 Answers2

0

You need to encode the URL query String, since not all characters are allowed in URLs. You can do this by calling addingPercentEncoding on the query String.

let baseUrl = "http://apis.data.go.kr/1471000/DrugPrdtPrmsnInfoService/getDrugPrdtPrmsnDtlInq"
let urlQuery = "?serviceKey=SERVICEKEY&item_name=\(drugName)&numOfRows=10&type=json"
guard let sanitisedUrl = urlQuery.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
    let url = URL(string:  baseUrl + urlQuery) else { return }

Alternatively, you can use URLComponents and set the query to the query property, which will sanitise the String automatically.

guard var urlComponents = URLComponents(string: "http://apis.data.go.kr/1471000/DrugPrdtPrmsnInfoService/getDrugPrdtPrmsnDtlInq") else { return }
urlComponents.query = "serviceKey=SERVICEKEY&item_name=\(drugName)&numOfRows=10&type=json"
guard let url = urlComponents.url else { return }
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
  • Thank you for you advice. The unwrapping problem seems to be solved, but another error message is showing; dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around line 1, column 0." UserInfo={NSDebugDescription=Invalid value around line 1, column 0., NSJSONSerializationErrorIndex=0}))) – WTH_MD Jan 05 '22 at 13:07
  • @WTH_MD that means that the response you receive is not JSON. You should investigate the issue further, firstly by printing the response as `String` and if you are still stuck, you should ask a new question, since this problem is unrelated to your original issue. – Dávid Pásztor Jan 05 '22 at 13:12
  • 1
    thanks to you I solved it. The problem was that "drugName" is inserted in korean, so it had to be encoded. After I encoded "drugName" with .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), all problem is solved! thank you!! – WTH_MD Jan 05 '22 at 15:22
  • 1
    @WTH_MD no need to percent encode it. You should construct your query using the queryItems https://stackoverflow.com/a/43668198/2303865 – Leo Dabus Jan 05 '22 at 20:20
0

try to add a guard before your dataTask

let url = "http://apis.data.go.kr/1471000/DrugPrdtPrmsnInfoService/getDrugPrdtPrmsnDtlInq?serviceKey=SERVICEKEY&item_name=\(drugName)&numOfRows=10&type=json"

guard let url = URL(string: urlString)?.absoluteURL else {
   return // a custom error, like NetworkError.badURL
}