SWIFT - Function to produce array using JSON data [duplicate] - arrays

class PostFOrData {
let url = NSURL( string: "http://210.61.209.194:8088/SmarttvWebServiceTopmsoApi/GetReadlist")
var picUrl = NSURL(string : "http://210.61.209.194:8088/SmarttvMedia/img/epi00001.png")
var responseString : NSString = ""
func forData() -> NSString {
let request = NSMutableURLRequest( URL: url!)
request.HTTPMethod = "POST"
var s : NSString = ""
let postString : String = "uid=59"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
println("error=\(error)")
return
} else {
println("response = \(response!)")
self.responseString = NSString(data: data, encoding: NSUTF8StringEncoding)!
println("responseString = \(self.responseString)")
}
}
// I want to return NSString here, but I always get nothing
return self.responseString
}
}
Anyone know how to get the data from task?

You can't return data directly from an asynchronous task.
The solution with Swift 2 is to make a completion handler like this:
class PostFOrData {
// the completion closure signature is (NSString) -> ()
func forData(completion: (NSString) -> ()) {
if let url = NSURL(string: "http://210.61.209.194:8088/SmarttvWebServiceTopmsoApi/GetReadlist") {
let request = NSMutableURLRequest( URL: url)
request.HTTPMethod = "POST"
let postString : String = "uid=59"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if let data = data,
jsonString = NSString(data: data, encoding: NSUTF8StringEncoding)
where error == nil {
completion(jsonString)
} else {
print("error=\(error!.localizedDescription)")
}
}
task.resume()
}
}
}
let pfd = PostFOrData()
// you call the method with a trailing closure
pfd.forData { jsonString in
// and here you get the "returned" value from the asynchronous task
print(jsonString)
}
That way, the completion is only called when the asynchronous task is completed. It is a way to "return" the data without actually using return.
Swift 3 version
class PostFOrData {
// the completion closure signature is (String) -> ()
func forData(completion: #escaping (String) -> ()) {
if let url = URL(string: "http://210.61.209.194:8088/SmarttvWebServiceTopmsoApi/GetReadlist") {
var request = URLRequest(url: url)
request.httpMethod = "POST"
let postString : String = "uid=59"
request.httpBody = postString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request) {
data, response, error in
if let data = data, let jsonString = String(data: data, encoding: String.Encoding.utf8), error == nil {
completion(jsonString)
} else {
print("error=\(error!.localizedDescription)")
}
}
task.resume()
}
}
}
let pfd = PostFOrData()
// you call the method with a trailing closure
pfd.forData { jsonString in
// and here you get the "returned" value from the asynchronous task
print(jsonString)
}

There are some very generic requirements that would like every good API Manager to satisfy: will implement a protocol-oriented API Client.
APIClient Initial Interface
protocol APIClient {
func send(_ request: APIRequest,
completion: #escaping (APIResponse?, Error?) -> Void)
}
protocol APIRequest: Encodable {
var resourceName: String { get }
}
protocol APIResponse: Decodable {
}
Now Please check complete api structure
// ******* This is API Call Class *****
public typealias ResultCallback<Value> = (Result<Value, Error>) -> Void
/// Implementation of a generic-based API client
public class APIClient {
private let baseEndpointUrl = URL(string: "irl")!
private let session = URLSession(configuration: .default)
public init() {
}
/// Sends a request to servers, calling the completion method when finished
public func send<T: APIRequest>(_ request: T, completion: #escaping ResultCallback<DataContainer<T.Response>>) {
let endpoint = self.endpoint(for: request)
let task = session.dataTask(with: URLRequest(url: endpoint)) { data, response, error in
if let data = data {
do {
// Decode the top level response, and look up the decoded response to see
// if it's a success or a failure
let apiResponse = try JSONDecoder().decode(APIResponse<T.Response>.self, from: data)
if let dataContainer = apiResponse.data {
completion(.success(dataContainer))
} else if let message = apiResponse.message {
completion(.failure(APIError.server(message: message)))
} else {
completion(.failure(APIError.decoding))
}
} catch {
completion(.failure(error))
}
} else if let error = error {
completion(.failure(error))
}
}
task.resume()
}
/// Encodes a URL based on the given request
/// Everything needed for a public request to api servers is encoded directly in this URL
private func endpoint<T: APIRequest>(for request: T) -> URL {
guard let baseUrl = URL(string: request.resourceName, relativeTo: baseEndpointUrl) else {
fatalError("Bad resourceName: \(request.resourceName)")
}
var components = URLComponents(url: baseUrl, resolvingAgainstBaseURL: true)!
// Common query items needed for all api requests
let timestamp = "\(Date().timeIntervalSince1970)"
let hash = "\(timestamp)"
let commonQueryItems = [
URLQueryItem(name: "ts", value: timestamp),
URLQueryItem(name: "hash", value: hash),
URLQueryItem(name: "apikey", value: "")
]
// Custom query items needed for this specific request
let customQueryItems: [URLQueryItem]
do {
customQueryItems = try URLQueryItemEncoder.encode(request)
} catch {
fatalError("Wrong parameters: \(error)")
}
components.queryItems = commonQueryItems + customQueryItems
// Construct the final URL with all the previous data
return components.url!
}
}
// ****** API Request Encodable Protocol *****
public protocol APIRequest: Encodable {
/// Response (will be wrapped with a DataContainer)
associatedtype Response: Decodable
/// Endpoint for this request (the last part of the URL)
var resourceName: String { get }
}
// ****** This Results type Data Container Struct ******
public struct DataContainer<Results: Decodable>: Decodable {
public let offset: Int
public let limit: Int
public let total: Int
public let count: Int
public let results: Results
}
// ***** API Errro Enum ****
public enum APIError: Error {
case encoding
case decoding
case server(message: String)
}
// ****** API Response Struct ******
public struct APIResponse<Response: Decodable>: Decodable {
/// Whether it was ok or not
public let status: String?
/// Message that usually gives more information about some error
public let message: String?
/// Requested data
public let data: DataContainer<Response>?
}
// ***** URL Query Encoder OR JSON Encoder *****
enum URLQueryItemEncoder {
static func encode<T: Encodable>(_ encodable: T) throws -> [URLQueryItem] {
let parametersData = try JSONEncoder().encode(encodable)
let parameters = try JSONDecoder().decode([String: HTTPParam].self, from: parametersData)
return parameters.map { URLQueryItem(name: $0, value: $1.description) }
}
}
// ****** HTTP Pamater Conversion Enum *****
enum HTTPParam: CustomStringConvertible, Decodable {
case string(String)
case bool(Bool)
case int(Int)
case double(Double)
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let string = try? container.decode(String.self) {
self = .string(string)
} else if let bool = try? container.decode(Bool.self) {
self = .bool(bool)
} else if let int = try? container.decode(Int.self) {
self = .int(int)
} else if let double = try? container.decode(Double.self) {
self = .double(double)
} else {
throw APIError.decoding
}
}
var description: String {
switch self {
case .string(let string):
return string
case .bool(let bool):
return String(describing: bool)
case .int(let int):
return String(describing: int)
case .double(let double):
return String(describing: double)
}
}
}
/// **** This is your API Request Endpoint Method in Struct *****
public struct GetCharacters: APIRequest {
public typealias Response = [MyCharacter]
public var resourceName: String {
return "characters"
}
// Parameters
public let name: String?
public let nameStartsWith: String?
public let limit: Int?
public let offset: Int?
// Note that nil parameters will not be used
public init(name: String? = nil,
nameStartsWith: String? = nil,
limit: Int? = nil,
offset: Int? = nil) {
self.name = name
self.nameStartsWith = nameStartsWith
self.limit = limit
self.offset = offset
}
}
// *** This is Model for Above Api endpoint method ****
public struct MyCharacter: Decodable {
public let id: Int
public let name: String?
public let description: String?
}
// ***** These below line you used to call any api call in your controller or view model ****
func viewDidLoad() {
let apiClient = APIClient()
// A simple request with no parameters
apiClient.send(GetCharacters()) { response in
response.map { dataContainer in
print(dataContainer.results)
}
}
}

Related

How to fetch data from nested array from API in SwiftUI?

this is my Model
public struct Welcome: Decodable{
public let userslist: [Userslist]
}
public struct Userslist: Decodable, Hashable{
public let full_name: String
public let partner_media: [PartnerMedia]
public init( partner_media: [PartnerMedia]) {
self.partner_media = partner_media
}
}
public struct PartnerMedia: Decodable , Hashable{
public var id = UUID()
public let url: String
public init( url: String) {
self.url = url
}
}
This is View Model I follow the MVVM pattern for accessing the data from API.
class PublisherModelVM: ObservableObject {
#Published var datas = [PartnerMedia]()
let url = "APIUrl"
init() {
getData(url: url)
}
func getData(url: String) {
guard let url = URL(string: url) else { return }
URLSession.shared.dataTask(with: url) { (data, _, _) in
if let data = data {
do {
let results = try JSONDecoder().decode(Welcome.self, from: data)
DispatchQueue.main.async {
self.datas = results.userslist `//Cannot assign value of type '[Userslist]' to type '[PartnerMedia]' what should I write for getting proper response`
}
}
catch {
print(error)
}
}
}.resume()
}
}
I want to fetch the url and full_name And set to the View
struct PublisherListView: View{
#StateObject var list = PublisherModelVM()
var body: some View{
ScrollView(.horizontal,showsIndicators: false){
ForEach(list.datas, id: \.id){ item in
Text(item.full_name)
AsyncImage(url: URL(string: item.url)){image in
image
.resizable()
.frame(width: 235, height: 125).cornerRadius(8)
}placeholder: {
Image(systemName: "eye") .resizable()
.frame(width: 235, height: 125).cornerRadius(8)
}
}
}
}
}
this Error show in my Xcode Cannot assign value of type '[Userslist]'
to type '[PartnerMedia]'
Please help me.
can anyone help me for recommending for API related full detailed
courses and thank you in advance
As I said before (in the questions you have deleted) pay attention to the details of your models to match the json data. Try this approach, works very well for me:
struct ContentView: View {
var body: some View {
PublisherListView()
}
}
struct ServerResponse: Decodable {
let userslist: [User]
}
struct User: Decodable, Identifiable {
let id: Int
let totalBooks: Int
let totalfollowers: Int
let fullAddress: String?
let partnerMedia: [PartnerMedia]
enum CodingKeys: String, CodingKey {
case id, totalBooks,totalfollowers
case partnerMedia = "partner_media"
case fullAddress = "full_address"
}
}
struct PartnerMedia: Decodable, Identifiable {
let id: Int
let url: String
}
struct PublisherListView: View{
#StateObject var list = PublisherModelVM()
var body: some View{
ScrollView(.horizontal,showsIndicators: false){
HStack(spacing:15) {
ForEach(list.datas, id: \.id){ item in
AsyncImage(url: URL(string: item.url)){ image in
image
.resizable()
.frame(width: 235, height: 125).cornerRadius(8)
} placeholder: {
Image(systemName: "eye") .resizable()
.frame(width: 235, height: 125).cornerRadius(8)
}
}
}
}
}
}
class PublisherModelVM: ObservableObject {
#Published var datas = [PartnerMedia]()
let url = "https://alibrary.in/api/publisherList"
init() {
getData(url: url)
}
func getData(url: String) {
guard let url = URL(string: url) else { return }
URLSession.shared.dataTask(with: url) { (data, _, _) in
if let data = data {
do {
let results = try JSONDecoder().decode(ServerResponse.self, from: data)
DispatchQueue.main.async {
for user in results.userslist {
self.datas.append(contentsOf: user.partnerMedia)
}
}
}
catch {
print(error)
}
}
}.resume()
}
}

How to delete and update structure type array in Core Data iOS Swift?

How to delete and update structure type array in Core Data iOS Sswift? I am saving to core data like this. I need to delete and update selected cell containing values
let projectsInfo = NSEntityDescription.insertNewObject(forEntityName:"ItemsInfo", into: delegate.persistentContainer.viewContext) as! ItemsInfo
let auditArray:[String:[lendingData]] = ["allcreditData":SaveWitnessData.shared.LendingDataArray]
let jsonData = try! JSONEncoder().encode(auditArray) projectsInfo.values = jsonData
delegate.saveContext()
And my struct is like
struct lendingData : Codable {
let userName : String
let amount : String
let date : String
let type : String
var witnessDetails : [witnessData]
}
Option 1.
Using a class and NSSecureCoding is the best way of doing this. The most flexible.
///To See the whole thing in action you have to follow a few steps
///Step 1. Create an new SwiftUI project with CoreData
///Step 2. Copy all the code in Option 1 into a `.swift` file
///Step 3. Go to the `Persistence.swift` file
/// Place these 2 lines
/// `WitnessDataTransformer.register()`
/// `LendingDataTransformer.register()`
/// Just under `container = NSPersistentCloudKitContainer(name: "YourAppName")
///Step 4. Go to the CoreData model
/// Select the `Item` Entity
/// Add a `lendingData` attribute of type `Transformable`
/// Update the `Transformer` and `Custom Class` in the `Data Model Inspector` as shown
///Step 5. You should see the View on Canvas in this point
Photo for Step 4
Code
import SwiftUI
//struct and class should start with an uppercase
//You need secureCoding not codable
//You have to change to class because NSSecurecoding is not available for a struct -https://developer.apple.com/documentation/foundation/nssecurecoding
public class LendingData : NSObject, Identifiable, ObservableObject{
public let id: String
#Published var userName : String
#Published var amount : String
#Published var date : String
#Published var type : String
//WitnessData needs to conform to secure coding as well
#Published var witnessDetails : [WitnessData]
static func sample() -> LendingData {
LendingData(id: UUID().uuidString, userName: "sample name", amount: "10.00", date: "\(Date())", type: "sample type", witnessDetails: [WitnessData.sample(), WitnessData.sample()])
}
static func blank() -> LendingData {
LendingData(id: UUID().uuidString, userName: "", amount: "", date: "", type: "", witnessDetails: [])
}
public enum CodingKeys: String, CodingKey {
case id
case userName
case amount
case date
case type
case witnessDetails
}
public init(id: String, userName : String, amount : String, date : String, type : String, witnessDetails : [WitnessData]) {
self.id = id
self.userName = userName
self.amount = amount
self.date = date
self.type = type
self.witnessDetails = witnessDetails
}
public required init?(coder: NSCoder) {
id = coder.decodeObject(forKey: CodingKeys.id.rawValue) as! String
userName = coder.decodeObject(forKey: CodingKeys.userName.rawValue) as! String
amount = coder.decodeObject(forKey: CodingKeys.amount.rawValue) as! String
date = coder.decodeObject(forKey: CodingKeys.date.rawValue) as! String
type = coder.decodeObject(forKey: CodingKeys.type.rawValue) as! String
witnessDetails = coder.decodeArrayOfObjects(ofClass: WitnessData.self, forKey: CodingKeys.witnessDetails.rawValue) ?? []
}
}
extension LendingData: NSSecureCoding{
public static var supportsSecureCoding: Bool{
return true
}
public func encode(with coder: NSCoder) {
coder.encode(id, forKey: CodingKeys.id.rawValue)
coder.encode(userName, forKey: CodingKeys.userName.rawValue)
coder.encode(amount, forKey: CodingKeys.amount.rawValue)
coder.encode(date, forKey: CodingKeys.date.rawValue)
coder.encode(type, forKey: CodingKeys.type.rawValue)
coder.encode(witnessDetails, forKey: CodingKeys.witnessDetails.rawValue)
}
}
///MUST CALL LendingDataTransformer.register() right after creating the Persistent Container before setup and loading store
#objc(LendingDataTransformer)
public final class LendingDataTransformer: NSSecureUnarchiveFromDataTransformer {
public static let name = NSValueTransformerName(rawValue: String(describing: LendingDataTransformer.self))
public override static var allowedTopLevelClasses: [AnyClass] {
return [LendingData.self, NSString.self, NSArray.self, WitnessData.self]
}
//Register before CoreData setup starts
#objc dynamic
public static func register() {
let transformer = LendingDataTransformer()
ValueTransformer.setValueTransformer(transformer, forName: name)
}
}
//You have to change to class because NSSecurecoding is not available for a struct -https://developer.apple.com/documentation/foundation/nssecurecoding
public class WitnessData: NSObject, Identifiable, ObservableObject{
public let id: String
//This is just a sample since you did not provide the struct
//Add your variables to
// the class,
// the CodingKeys,
// init?(coder: NSCoder),
// encode(with coder: NSCoder), and
// init(id: String, name : String).
// Just follow the pattern.
#Published var name: String
static func sample() -> WitnessData{
WitnessData(id: UUID().uuidString, name: UUID().uuidString)
}
static func blank() -> WitnessData{
WitnessData(id: UUID().uuidString, name: "")
}
public enum CodingKeys: String, CodingKey {
case id
case name
}
public init(id: String, name : String) {
self.id = id
self.name = name
}
public required init?(coder: NSCoder) {
id = coder.decodeObject(forKey: CodingKeys.id.rawValue) as? String ?? ""
name = coder.decodeObject(forKey: CodingKeys.name.rawValue) as? String ?? ""
}
}
extension WitnessData: NSSecureCoding{
public static var supportsSecureCoding: Bool{
return true
}
public func encode(with coder: NSCoder) {
coder.encode(id, forKey: CodingKeys.id.rawValue)
coder.encode(name, forKey: CodingKeys.name.rawValue)
}
}
///MUST CALL WitnessDataTransformer.register() right after creating the Persistent Container before setup and loading store
#objc(WitnessDataTransformer)
public final class WitnessDataTransformer: NSSecureUnarchiveFromDataTransformer {
public static let name = NSValueTransformerName(rawValue: String(describing: WitnessDataTransformer.self))
public override static var allowedTopLevelClasses: [AnyClass] {
return [WitnessData.self, NSString.self, NSArray.self]
}
//Register before CoreData setup starts
#objc dynamic
public static func register() {
let transformer = WitnessDataTransformer()
ValueTransformer.setValueTransformer(transformer, forName: name)
}
}
The below SwiftUI code works for both option 1 or option 2
///This is just a sample View
struct LendingDataView: View {
//You will need the original ObservableObject if you want to be able to show changes
//SwiftUI depends on being told that there are chagnes so it can reload Views
#ObservedObject var item: Item
var body: some View {
if item.lendingData != nil{
List{
TextField("username",text: $item.lendingData.bound.userName)
TextField("amount",text: $item.lendingData.bound.amount)
TextField("date",text: $item.lendingData.bound.date)
TextField("type",text: $item.lendingData.bound.type)
Section(content: {
ForEach($item.lendingData.bound.witnessDetails, content: { $witness in
HStack{
TextField("name",text: $witness.name)
Spacer()
//For deleting by object
Image(systemName: "trash")
.foregroundColor(.red)
.onTapGesture {
let idx = item.lendingData!.witnessDetails.firstIndex(where: {
$0.id == witness.id
})
if idx != nil{
item.lendingData!.witnessDetails.remove(at: idx!)
}
//Because you are so far down the line you have to tell the ObservableObject there is a change
//If you dont you won't see the new items until something happens to trigger a refresh
//item.objectWillChange.send()
item.objectWillChange.send()
}
}
})
//For deleting by index
.onDelete(perform: { indexSet in
for idx in indexSet{
item.lendingData!.witnessDetails.remove(at: idx)
}
})
}, header: {
HStack{
Text("Witness Data")
Button(action: {
item.lendingData!.witnessDetails.append(WitnessData.blank())
//Because you are so far down the line you have to tell the ObservableObject there is a change
//If you dont you won't see the new items until something happens to trigger a refresh
item.objectWillChange.send()
}, label: {
Image(systemName: "plus")
})
}
})
}
}else{
VStack{
Text("no lending data")
Button(action: {
item.lendingData = LendingData.blank()
}, label: {
Image(systemName: "plus")
})
}
}
}
}
//Standard Preview
struct LendingDataView_Previews: PreviewProvider {
//Use the preview container
static let context = PersistenceController.preview.container.viewContext
static var sampleItem = Item(context: context)
static var previews: some View {
LendingDataView(item: sampleItem)
}
}
extension Optional where Wrapped == LendingData {
var _bound: LendingData? {
get {
return self
}
set {
self = newValue
}
}
var bound: LendingData {
get {
return _bound ?? LendingData.blank()
}
set {
_bound = newValue
}
}
}
Like I said at the start class is the safest way but you can use the struct.
Option 2
Just add an an attribute named lendingDataJSON of Type String? INSTEAD of the lendingData of type Transformable
struct LendingData : Codable, Identifiable{
let id: String
var userName : String
var amount : String
var date : String
var type : String
var witnessDetails : [WitnessData]
static func sample() -> LendingData {
LendingData(id: UUID().uuidString, userName: "sample name", amount: "10.00", date: "\(Date())", type: "sample type", witnessDetails: [WitnessData.sample(), WitnessData.sample()])
}
static func blank() -> LendingData {
LendingData(id: UUID().uuidString, userName: "", amount: "", date: "", type: "", witnessDetails: [])
}
}
struct WitnessData: Codable, Identifiable{
let id: String
var name: String
static func sample() -> WitnessData{
WitnessData( id: UUID().uuidString, name: UUID().uuidString)
}
static func blank() -> WitnessData{
WitnessData( id: UUID().uuidString, name: "")
}
}
//The App's CoreData Model will need an attibute
// named lendingDataJSON of Type String
extension Item{
//This computed property should be the only way that the app alters the LendingData
//If you use the lendingDataJSON directly you can corrupt all of it
var lendingData: LendingData?{
get{
let decoder = JSONDecoder()
if let obj = try? decoder.decode(LendingData.self, from: self.lendingDataJSON?.data(using: .utf8) ?? Data()) {
return obj
}else{
return nil
}
}
set{
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
if let encoded = try? encoder.encode(newValue) {
self.lendingDataJSON = String(data: encoded, encoding: .utf8) ?? ""
}
}
}
}
All the View code will work the same with the class option or with the struct option

swift 5: how to check array generic type?

var array: Array<Int>? = nil
var arrayType: Any.Type = type(of: array)
print("type:\(arrayType)")
I got printed:
type:Optional<Array<Int>>
then, how can i get the type Int from arrayType?
You may not understand why I did this. The actual situation is:
I have a bean, like this:
protocol Initializable {
init()
}
class MyBean1: Initializable {
required init() {}
var property1: Int?
var property2: String?
}
class MyBean2: Initializable {
required init() {}
var beans: Array<MyBean1>?
}
I have json data like this:
{beans:[{"property1":1,"property2":"string1"},{"property1":2,"property2":"string2"}]}
I want automatic create object and set the values.
I use the Runtime(A Swift Runtime library for viewing type info, and the dynamic getting and setting of properties.) Framework to mirror and set properties.
I extend the TypeInfo:
extension TypeInfo {
func properties() -> [String] {
var properties: [String] = []
for property in self.properties {
properties.append(property.name)
}
return properties
}
}
I want create object from json string:
static func fromJson<Result: Initializable>(json: String, type: Result.Type) -> Result {
var result: Initializable = Result.init()
if let dictionary = Dictionary<String, Any>.from(json: json) {
if let info: TypeInfo = try? typeInfo(of: type(of: result)) {
let properties = info.properties()
for (key, value) in dictionary {
if properties.contains(key) {
if let property: PropertyInfo = try? info.property(named: key) {
print("\(key):\(property.type)")
}
}
}
}
}
return result as! Result
}
I got print:
beans:Optional<Array<MyBean1>>
the property.type type is Any.Type.
I want get the type MyBean1 and create MyBean1's object from property.type.
Now i use Bundle.main.classNamed to get the generic type.
TypeName got from substring
var typeName = "\(property.type)" // Optional<Array<MyBean1>>
if let range = typeName.range(of: "Optional<") {
typeName = typeName.replacingCharacters(in: range, with: "")
typeName = String(typeName[typeName.startIndex..<(typeName.index(before: typeName.endIndex))])
}
print("typeName:\(typeName)") // Array<MyBean1>
if let range = typeName.range(of: "Array<") {
typeName = typeName.replacingCharacters(in: range, with: "")
typeName = String(typeName[typeName.startIndex..<(typeName.index(before: typeName.endIndex))])
print("typeName:\(typeName)") // MyBean1
if let namespace = Bundle.main.infoDictionary?["CFBundleExecutable"] as? String {
let clazz: AnyClass? = Bundle.main.classNamed("\(namespace).\(typeName)")
if let initableType = clazz as? Initializable.Type {
var beans = Array<Any>()
for item in array {
var bean = initableType.init()
// set bean properties
beans.append(bean)
}
}
}
}

Filter an array by a second array when both arrays are defined by its own struct

I'm trying to filter theDataArray by theCaseDataArray where dataName in theDataArray matches the dataName in theCaseDataArray. As you can see by the code, each array is defined by its own struct. I've marked the line in the code where I need help. I've tried using a $0 and everything I can think of but no joy. I know there are a number of similar question on the forum but none see to contain an answer to this particular situation.
import UIKit
import SQLite
struct Data_On_Case
{
var dataID: Int64
var dataName: String
}
struct MyData
{
let dataID: Int64
var dataName: String
var dataType: String?
var dataDescription: String?
var pricePaid: Double?
var shipping: Double?
var datePurchased: String?
var dataDuration: String?
var manufacturer: String?
var venue: String?
var performanceLevel: String?
var dataNotes: String?
var dataStyle: String?
}
class Test_VC: UIViewController
{
private let crossRefTable = Table("CrossRefCase_Data")
private let crossRefRCaseID = Expression<Int64>("CaseID_CaseXRef")
private let crossRefDataID = Expression<Int64>("DataID_CaseXRef")
private var theDataArray = [MyData]()
private let theDataTable = Table("My_Data")
private let dataID = Expression<Int64>("DataID")
private let data_Name = Expression<String>("Data_Name")
private var searchBarShowing: Bool = false
private var isSearching: Bool = false
private var searchingArray = [MyData]()
private var theCurrentArray = [MyData]()
private var theCaseDataArray = [Data_On_Case]()
#IBOutlet weak var theSearchBar: UISearchBar!
override func viewDidLoad()
{
super.viewDidLoad()
}
}
extension Test_VC: UISearchBarDelegate
{
func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int)
{
switch selectedScope
{
case 0:
searchingArray = theDataArray
isSearching.toggle()
case 1:
// Cannot convert value of type '((Data_On_Case) throws -> Bool) throws -> Bool' to expected argument type '(MyData) throws -> Bool'
// The line below is where I'm stuck. The error is shown above.
searchingArray = theDataArray.filter(theCaseDataArray.contains(where: ))
isSearching = true
self.theSearchBar.resignFirstResponder()
theSearchBar.showsScopeBar = true
default:
return
}
}
}
Use filter as below,
searchingArray = theDataArray.filter { data in
return self.theCaseDataArray.contains(where: { $0.dataName == data.dataName })
}

Converting response NSArray to Object array swift3

Hi i am able to get response from server for array list. But i dont know how to parse that response in object array [Feed] and send it on on completion handler. My Code is as follows:
class FeedsService {
private var feedsEndPoint: String = "https://jsonplaceholder.typicode.com/posts"
public func getFeeds(completion: ([Feed]) -> Void) {
Alamofire.request(feedsEndPoint, method: .get)
.validate(statusCode: 200..<300)
.validate(contentType: ["application/json"])
.responseJSON{ response in
print("Response \(response.result.value)")
}
}
}
Feed Model is as follows:
class Feed {
private var title: String
private var body: String
init(title:String, body: String) {
self.title = title
self.body = body
}
public func getTitle() -> String {
return self.title
}
public func getBody() -> String {
return self.body;
}
}
I want to parse this as Feed Array and sent it on completion callback.
I am using Alamofire rest library for loading data from rest server.
You can try this:
class FeedsService {
private var feedsEndPoint: String = "https://jsonplaceholder.typicode.com/posts"
public func getFeeds(completion: #escaping ([Feed]) -> Void) {
Alamofire.request(feedsEndPoint, method: .get)
.validate(statusCode: 200..<300)
.validate(contentType: ["application/json"])
.responseJSON{ response in
print("Response \(response.result.value)")
var feeds = [Feed]()
if let jsonArray = response.result.value as? [[String: Any]] {
for json in jsonArray {
if let feed = Feed(json: json) {
feeds.append(feed)
}
}
completion(feeds)
} else {
// handle error
}
}
}
}
Also, update your Feed class:
class Feed {
private var title: String
private var body: String
init(title:String, body: String) {
self.title = title
self.body = body
}
init?(json: [String: Any]) {
guard let title = json["title"] as? String,
let body = json["body"] as? String else {
return nil
}
self.title = title
self.body = body
}
public func getTitle() -> String {
return self.title
}
public func getBody() -> String {
return self.body;
}
}
Just change "title" and "body" to whatever is the appropriate key in your json response.
As El Tomato is pointing out that Feed init is not working, this is a test code that can be tried out in a playground:
let testFeedJson = ["title": "Test Title", "body" : "Test Body"]
if let testFeed = Feed(json: testFeedJson) {
print(testFeed.getTitle())
print(testFeed.getBody())
}

Resources