If you want to make your loadData generic and access the property results of decodedResponse,
You need to tell that type T has a property named results.
For example:
struct Response: Codable {
		var results: [Result]
}
struct Result: Codable {
		var trackId: Int
		var trackName: String
		var collectionName: String
}
protocol HoldingResults {
		associatedtype R
		var results: [R] {get}
}
extension Response: HoldingResults {}
As you see, the protocol HoldingResults is used to tell Swift that the type conforming to it has a property named results.
You can define your loadData using the protocol:
		func loadData<T: Decodable>(model: T.Type, completion: @escaping ([T.R])->Void)
		where T: HoldingResults
		{
				guard let url = URL(string: "https://itunes.apple.com/search?term=taylor+swift&entity=song") else {
						print("Invalid URL")
						return
				}
				let request = URLRequest(url: url)
				URLSession.shared.dataTask(with: request) { data, response, error in
						if let data = data {
								do {
										let decodedResponse = try JSONDecoder().decode(model, from: data)
										DispatchQueue.main.async {
												print(decodedResponse)
												completion(decodedResponse.results)
										}
										return
								} catch {
										print(error)
								}
						}
						print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
				}
				.resume()
		}
And use it as:
				loadData(model: Response.self) {
						self.results = $0
				}
(I replaced if-let-try? to do-try-catch, that's my preference and not required.)