I am trying to fetch a data from UserDefault but when I am doing this I am getting error
var sharedPreference: UserDefaults = UserDefaults.init(suiteName: "user-key-value")!
func getLastLoginClientId() -> Int64? {
for (key, value) in sharedPreference.dictionaryRepresentation() {
if key == LAST_USER {
return value as! Int64
}
}
return nil
}
I am getting that my key is having some value but when returning it, it throws error.
This is how I save
func setLastLoginClientId(clientId: Int64) {
sharedPreference.set(clientId, forKey: LAST_USER)
sharedPreference.synchronize()
}
I think you could do something as simple as
func getLastLoginClientId() -> Int64? {
return sharedPreference.value(forKey: LAST_USER) as? Int64
}
Here is what I've tested
struct CustomUserDefaults {
var sharedPreference : UserDefaults = UserDefaults.init(suiteName: "user-key-value")!
let LAST_USER = "test"
func test() {
let value = Int64(20.0)
self.setLastLoginClientId(value)
let testValue = getLastLoginClientId()
print(testValue) // 20.0
}
func setLastLoginClientId(_ value: Int64) {
sharedPreference.set(value, forKey: LAST_USER)
}
func getLastLoginClientId() -> Int64? {
return sharedPreference.value(forKey: LAST_USER) as? Int64
}
}
This code leads to crash somewhere later with EXC_BAD_ACCESS
SomeLoader().selectedIndex = 1
class SomeLoader {
// MARK: - Public
var selectedIndex: Int? {
get {
return dataStorage.selectedIndex
}
set {
dataStorage.selectedIndex = newValue
}
}
}
this code is not crashed:
SomeLoader().selectedIndex = 1
class SomeLoader {
// MARK: - Public
var selectedIndex: Int? {
get {
return dataStorage.selectedIndex
}
set {
dataStorage.updateSelected(index: newValue)
}
}
}
where:
struct DataStorage<T: Hashable> {
enum Keys: String {
case selectedIndex
}
private func get<U>(forKey key: String) -> U? {
guard let objectData = getData(forKey: key) else {
return nil
}
let object: U? = get(forData: objectData)
return object
}
private func get<U>(forData objectData: Data) -> U? {
return NSKeyedUnarchiver.unarchiveObject(with: objectData) as? U
}
private func save<U>(forKey key: String, object: U) {
let encodedData = NSKeyedArchiver.archivedData(withRootObject: object)
UserDefaults.standard.set(encodedData, forKey: key)
}
}
extension DataStorage {
func updateSelected(index: Int?) {
guard let index = index else {
remove(forKey: Keys.selectedIndex.rawValue)
return
}
saveSelected(index: index)
}
var selectedIndex: Int? {
get {
return get(forKey: Keys.selectedIndex.rawValue)
}
set {
guard let index = newValue else {
remove(forKey: Keys.selectedIndex.rawValue)
return
}
saveSelected(index: index)
}
}
}
Why? Is it a bug?
Screenshots with an error and a callstack. The error appears later in the other part of the code.
The code below crashes in the iOS. But works in the playground.
//: Playground - noun: a place where people can play
import UIKit
struct DataStorage<T: Hashable> {
enum Keys: String {
case selectedIndex
}
private func get<U>(forKey key: String) -> U? {
guard let objectData = getData(forKey: key) else {
return nil
}
let object: U? = get(forData: objectData)
return object
}
private func get<U>(forData objectData: Data) -> U? {
return NSKeyedUnarchiver.unarchiveObject(with: objectData) as? U
}
private func save<U>(forKey key: String, object: U) {
let encodedData = NSKeyedArchiver.archivedData(withRootObject: object)
UserDefaults.standard.set(encodedData, forKey: key)
}
private func remove(forKey key: String) {
UserDefaults.standard.removeObject(forKey: key)
}
private func saveSelected(index: Int) {
save(forKey: Keys.selectedIndex.rawValue, object: index)
}
private func getData(forKey key: String) -> Data? {
return getContent(forKey: key) as? Data
}
private func getContent(forKey key: String) -> Any? {
return UserDefaults.standard.value(forKey: key)
}
}
extension DataStorage {
func updateSelected(index: Int?) {
guard let index = index else {
remove(forKey: Keys.selectedIndex.rawValue)
return
}
saveSelected(index: index)
}
var selectedIndex: Int? {
get {
return get(forKey: Keys.selectedIndex.rawValue)
}
set {
guard let index = newValue else {
remove(forKey: Keys.selectedIndex.rawValue)
return
}
saveSelected(index: index)
}
}
}
class SomeLoader {
// MARK: - Public
var dataStorage = DataStorage<Int>()
var selectedIndex: Int? {
get {
return dataStorage.selectedIndex
}
set {
dataStorage.selectedIndex = newValue
}
}
}
let someLoader = SomeLoader()
someLoader.selectedIndex = 1
print(someLoader)
The code below works everywhere
//: Playground - noun: a place where people can play
import UIKit
struct DataStorage<T: Hashable> {
enum Keys: String {
case selectedIndex
}
private func get<U>(forKey key: String) -> U? {
guard let objectData = getData(forKey: key) else {
return nil
}
let object: U? = get(forData: objectData)
return object
}
private func get<U>(forData objectData: Data) -> U? {
return NSKeyedUnarchiver.unarchiveObject(with: objectData) as? U
}
private func save<U>(forKey key: String, object: U) {
let encodedData = NSKeyedArchiver.archivedData(withRootObject: object)
UserDefaults.standard.set(encodedData, forKey: key)
}
private func remove(forKey key: String) {
UserDefaults.standard.removeObject(forKey: key)
}
private func saveSelected(index: Int) {
save(forKey: Keys.selectedIndex.rawValue, object: index)
}
private func getData(forKey key: String) -> Data? {
return getContent(forKey: key) as? Data
}
private func getContent(forKey key: String) -> Any? {
return UserDefaults.standard.value(forKey: key)
}
}
extension DataStorage {
func updateSelected(index: Int?) {
guard let index = index else {
remove(forKey: Keys.selectedIndex.rawValue)
return
}
saveSelected(index: index)
}
var selectedIndex: Int? {
get {
return get(forKey: Keys.selectedIndex.rawValue)
}
set {
guard let index = newValue else {
remove(forKey: Keys.selectedIndex.rawValue)
return
}
saveSelected(index: index)
}
}
}
class SomeLoader {
// MARK: - Public
var dataStorage = DataStorage<Int>()
var selectedIndex: Int? {
get {
return dataStorage.selectedIndex
}
set {
dataStorage.updateSelected(index: newValue)
}
}
}
let someLoader = SomeLoader()
someLoader.selectedIndex = 1
print(someLoader)
I have a database with some tables, each table represents a object of my project. I want write a generic function to read, by SQL, a table and create a object with the records readed. So, the parameters of my function are: Table Name and Object Type. The code below is my func to do this. In the end of func, I tries call what I would like to do, but with a especific object, that's don't the I want.
func readAll<T>(objeto: String, typeClass: T.Type) -> [T] {
var ret : [T] = []
// STATEMENT DATA
let queryString = "SELECT * FROM \(objeto);"
var queryStatement: OpaquePointer? = nil
// STATEMENT DATA TYPE
let queryString2 = "PRAGMA table_info(\(objeto));"
var queryStatement2: OpaquePointer? = nil
// 1
if sqlite3_prepare_v2(db,queryString,-1,&queryStatement,nil) != SQLITE_OK {
print("Error to compile readAll \(objeto) 1")
return ret
}
if sqlite3_prepare_v2(db,queryString2,-1,&queryStatement2,nil) != SQLITE_OK {
print("Error to compile readAll \(objeto) 2")
return ret
}
var listNameColumns : [String] = []
while( sqlite3_step(queryStatement2) == SQLITE_ROW ) {
listNameColumns.append( String(cString: sqlite3_column_text(queryStatement2, 2)!) )
}
// 2
while ( sqlite3_step(queryStatement) == SQLITE_ROW ) {
var dict: [String:Any] = [:]
for i in 0...listNameColumns.count-1 {
let nameColumn = String(cString: sqlite3_column_name(queryStatement,Int32(i))!)
switch (sqlite3_column_type(queryStatement, Int32(i))) {
case SQLITE_TEXT:
dict[nameColumn] = String(cString: sqlite3_column_text(queryStatement, Int32(i))!)
break
case SQLITE_INTEGER:
dict[nameColumn] = sqlite3_column_int(queryStatement, Int32(i))
break
case SQLITE_FLOAT:
dict[nameColumn] = sqlite3_column_double(queryStatement, Int32(i))
break
default:
print("Tipo desconhecido.")
break
}
}
ret.append(ResPartner(dict: dict)) <------ HERE IS MY QUESTION!
}
// 3
sqlite3_finalize(queryStatement2)
sqlite3_finalize(queryStatement)
return ret
}
Here are two objects, They are a bit different, but the builder works the same and the fields as well.
class ResPartner {
static let fieldsResPartner : [String] = ["id","company_type_enum_for_customer","name","contact_address","customer_account_number","customer_group_id","segment_id","subsegment_id","economic_group_id","street","category_id","type_stablishment_id","final_user","final_taxpayer","cnpj_cpf","inscr_est","ccm","cnae","phone","phone_extension","mobile","fax","email","email_extra","website","lang"]
var attributes : [String:Any] = [:]
init(dict : [String:Any]) {
for k in dict.keys {
if(ResPartner.fieldsResPartner.contains(k)) {
attributes[k] = dict[k]
}
}
}
func toString() {
for k in attributes.keys{
print("\(k) - \(attributes[k]!)")
}
}
}
class Product {
static let fieldsProducts : [String] = ["id","name","default_code","display_name","categ_id","company_ax_id","destination_type","fiscal_class_code","multiple","taxes_id","uom_id","uom_po_id","__last_update","active","create_date","create_uid","currency_id","invoice_police","item_ids","list_price","price","pricelist_id","type"]
public var default_code: String!
public var display_name: String!
public var id: Int!
public var name: String!
public var destination_type: String!
public var company_ax_id: Int!
public var categ_id: Int!
public var fiscal_class_code: String!
public var taxes_id: Int!
public var uom_id: Int!
public var uom_po_id: Int!
public var multiple: Int!
public var last_update: String!
public var active: Bool!
public var create_date: String!
public var create_uid: Int!
public var currency_id: Int!
public var invoice_police: String!
public var item_ids: [Int]!
public var list_price: String!
public var price: Float!
public var pricelist_id: Int!
public var type: String!
init() {
}
init( dict : [String:Any] ) {
self.default_code = dict["default_code"] as! String
self.display_name = dict["display_name"] as! String
self.id = dict["id"] as! Int
self.name = dict["name"] as! String
self.destination_type = dict["destination_type"] as! String
self.company_ax_id = dict["company_ax_id"] as! Int
self.categ_id = dict["categ_id"] as! Int
self.fiscal_class_code = dict["fiscal_class_code"] as! String
self.taxes_id = dict["taxes_id"] as! Int
self.uom_id = dict["uom_id"] as! Int
self.uom_po_id = dict["uom_po_id"] as! Int
self.multiple = dict["multiple"] as! Int
self.last_update = dict["last_update"] as! String
self.active = dict["active"] as! Bool
self.create_date = dict["create_date"] as! String
self.create_uid = dict["create_uid"] as! Int
self.currency_id = dict["currency_id"] as! Int
self.invoice_police = dict["invoice_police"] as! String
self.item_ids = dict["item_ids"] as! [Int]
self.list_price = dict["list_price"] as! String
self.price = dict["price"] as! Float
self.pricelist_id = dict["pricelist_id"] as! Int
self.type = dict["type"] as! String
}
}
So, my question is, How I call the constructor of T.Type class passed by parameter? I did read about protocols, extensions, other posts, but not solves my problem.
You can constrain your generic with protocol:
Define a protocol for initializing with a dictionary:
protocol DictionaryInitializable {
init(dict: [String: Any])
}
Make your two types conform to that type (you'll have to add required to your init methods, as prompted by Xcode), e.g.:
class Product: DictionaryInitializable {
...
required init(dict: [String: Any]) {
...
}
}
and
class ResPartner: DictionaryInitializable {
static let fieldsResPartner = ...
var attributes: [String: Any] = [:]
required init(dict: [String: Any]) {
for k in dict.keys where ResPartner.fieldsResPartner.contains(k) {
attributes[k] = dict[k]
}
}
func toString() { ... }
}
Change your method declaration to make it clear that T must conform to your new protocol:
func readAll<T: DictionaryInitializable>(objeto: String, typeClass: T.Type) -> [T] {
var ret: [T] = []
...
// 2
while ( sqlite3_step(queryStatement) == SQLITE_ROW ) {
var dict: [String: Any] = [:]
...
ret.append(T(dict: dict)) // You can now use `T` here
}
return ret
}
And you’d call it like:
let list = db_respartner.readAll(objeto: "res_partner", typeClass: ResPartner.self)
Create a Protocol with init Method
protocol Mappable {
init(dictionary:[String:AnyObject]) // Changed based on your requirement.
}
Conform your protocol in ResPartner.
class ResPartner: Mappable {
required init(dictionary : [String : AnyObject]) {
// initialize here
}
}
Conform your protocol in Product.
class Product: Mappable {
required init(dictionary : [String : AnyObject]) {
// initialize here
}
}
Create a custom objects
func readAll<T:Mappable>(objeto: String, typeClass: T.Type) -> [T] {
var ret : [T] = []
// intialize your variable
let obj = typeClass.init(dictionary: ["":"" as AnyObject])
return ret
}
I have used Alamofire and SwiftyJSON To Populate the UiCollectionview and its working fine but didSelectItemAtIndexPath function shows array out of index thought I have printed the array count and it's not empty
any suggestion
here is my code:-
The model
import Foundation
class ProductModel {
private var _ProductItemId: String!
private var _ProductMainCategory: String!
private var _ProductCategoryId: String!
private var _ProductName: String!
private var _ProductItemNo: String!
private var _ProductAvalaibility: String!
private var _ProductSeoDesc: String!
private var _ProductImageURL: String!
private var _ProductBrand_ID: String!
private var _ProductCat_name: String!
//Level 1
private var _ProductTotalQuantity : String!
private var _Productprice : String!
private var _ProductSalePrice : String!
private var _ProductWeightName : String!
private var _ProductCode : String!
var ProductItemId : String {
return _ProductItemId
}
var ProductMainCategory : String {
return _ProductMainCategory
}
var ProductCategoryId : String {
return _ProductCategoryId
}
var ProductName : String {
return _ProductName
}
var ProductItemNo : String {
return _ProductItemNo
}
var ProductAvalaibility : String {
return _ProductAvalaibility
}
var ProductSeoDesc : String {
return _ProductSeoDesc
}
var ProductImageURL : String {
return _ProductImageURL
}
var ProductBrand_ID: String {
return _ProductBrand_ID
}
var ProductCat_name: String {
return _ProductCat_name
}
//Level 1
var ProductTotalQuantity : String {
return _ProductTotalQuantity
}
var Productprice : String {
return _Productprice
}
var ProductSalePrice : String {
return _ProductSalePrice
}
var ProductWeightName : String {
return _ProductWeightName
}
var ProductCode : String {
return _ProductCode
}
//Initilizer
init(ProductImageURL : String, ProductName : String, Productprice : String, ProductSalePrice : String)
{
self._ProductName = ProductName
self._ProductImageURL = ProductImageURL//
//Level 1
self._Productprice = Productprice//
self._ProductSalePrice = ProductSalePrice//
}
My CollectionView Delegates and Data sources
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCellWithReuseIdentifier("ProductCell", forIndexPath: indexPath)as? ProductCell {
let _prod: ProductModel!
_prod = prod [indexPath.row]
cell.configureCell(_prod)
return cell
}
else{
return UICollectionViewCell()
}
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let prodDetail: ProductModel!
prodDetail = prod[indexPath.row] //error Array index out of range
print(prodDetail.Productprice)
performSegueWithIdentifier("productDetailSegue", sender: prodDetail)
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//if inSearchMode{
//return filteredProd.count
// }
return prod.count
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
Calling API and Parsing
Alamofire.request(.POST, "http://www.picknget.com/webservice/index.php/Home/filter_grocery_product_practice/", parameters: parameterDictionary as? [String : AnyObject])
.responseJSON { response in
if let value = response.result.value {
let json = JSON(value)
print(json)
if let _statusCode = json["status"].string {
// print("the ststus code is ", _statusCode)
if (_statusCode == "1"){
self.parseJSON(json)
}
if (_statusCode == "0"){
SwiftSpinner.hide({
self.callAlert("OOP's", _msg: "No More Product is available in this section right now")
})
}
}
//print ("json result ", json)
}
}.responseString { response in
//print("response ",response.result.value)
}
}
func parseJSON(json: JSON) {
for result in json["cat"].arrayValue {
let name = result["Name"]
let aString: String = "\(result["ImageURL"])"
let product_Image_Url = aString.stringByReplacingOccurrencesOfString("~", withString: "http://www.picknget.com", options: NSStringCompareOptions.LiteralSearch, range: nil)
let price = result["cat_price"][0]["Price"].string
let SalePrice = result["cat_price"][0]["SalePrice"].string
let product = ProductModel(ProductImageURL: "\(product_Image_Url)", ProductName: "\(name)", Productprice: "\(price!)", ProductSalePrice: "\(SalePrice!)")
prod.append(product)
}
print("########")
print(prod.count)
dispatch_async(dispatch_get_main_queue(),{
self.productCollect.reloadData()
});
}
According your comments, I believe the issue is related to how you set the obtained Products for the Collection View.
It's very likely that the function parseJSON executes on a secondary thread. This is actually, the same execution context of the completion handler of method responseJSON.
Within function parseJSON you have this statement:
prod.append(product)
Here, prod should not be a global variable or not a member variable of the view controller! Make it a local variable in function parseJSON!
Your view controller should have a property of this array as well, e.g. products. This serves as the "model" of the view controller. It will be accesses only from the main thread.
In parseJSON assign the view controller the products as follows:
func parseJSON(json: JSON) {
var tmpProducts: [Product] = []
for result in json["cat"].arrayValue {
let name = result["Name"]
let aString: String = "\(result["ImageURL"])"
let product_Image_Url = aString.stringByReplacingOccurrencesOfString("~", withString: "http://www.picknget.com", options: NSStringCompareOptions.LiteralSearch, range: nil)
let price = result["cat_price"][0]["Price"].string
let SalePrice = result["cat_price"][0]["SalePrice"].string
let product = ProductModel(ProductImageURL: "\(product_Image_Url)", ProductName: "\(name)", Productprice: "\(price!)", ProductSalePrice: "\(SalePrice!)")
tmpProducts.append(product)
}
dispatch_async(dispatch_get_main_queue(),{
self.products = tmpProducts // assuming `self` is the ViewController
self.productCollect.reloadData()
});
}
Note: you need to change your Data Source Delegates accordingly, e.g. accessing the "model" (self.products.count) etc.
If anyone has any experience working with Parse using Swift, specifically subclassing PFObject..... I cannot figure out why the saveinbackground call below is throwing the above error?
Thanks!
func saveNewPerson(name: String) {
var myPeeps = [Person]()
if let currentUser = PFUser.currentUser() {
if currentUser.valueForKey("myPeeps")?.count < 1 {
myPeeps = []
} else {
myPeeps = currentUser.valueForKey("myPeeps") as! [Person]
}
let newPerson = Person(name: name, stores: [:])
myPeeps.append(newPerson)
currentUser.setObject(myPeeps, forKey: "myPeeps")
println(currentUser.valueForKey("myPeeps")?.count)
//WHY DOES THIS SAVE THROW ERROR FOR NOT INITIALZING?
currentUser.saveInBackgroundWithBlock{ succeeded, error in
if succeeded {
//3
println("Saved")
} else {
//4
if let errorMessage = error?.userInfo?["error"] as? String {
self.showErrorView(error!)
}
}
}
}
}
This is my Person class:
class Person: PFObject, PFSubclassing {
override class func initialize() {
struct Static {
static var onceToken : dispatch_once_t = 0;
}
dispatch_once(&Static.onceToken) {
self.registerSubclass()
}
}
static func parseClassName() -> String {
return "Person"
}
var name: String = ""
var stores: [String : Store] = [:]
init(name: String, stores: [String : Store]) {
self.name = name
self.stores = stores
super.init()
}
}
My Store Class:
class Store: PFObject, PFSubclassing {
override class func initialize() {
struct Static {
static var onceToken : dispatch_once_t = 0;
}
dispatch_once(&Static.onceToken) {
self.registerSubclass()
}
}
static func parseClassName() -> String {
return "Store"
}
var name: String = ""
var clothingSizes: [String: String] = [:]
init(name: String, clothingSizes: [String: String]){
self.name = name
self.clothingSizes = clothingSizes
super.init()
}
}
For both Parse subclasses, you need to make your inits convenience inits. Basically, what's going on is there is no implementation of init(), which you could do, by calling
override init() {
super.init()
}
Another option is to make your init a convenience init, and calling self.init()
convenience init(name: String, stores: [String : Store]) {
self.init()
self.name = name
self.stores = stores
}