I'm new to coding and I'm trying to create a password generator. I've created one using a single array of strings (all lowercase or all uppercase). But I want to create using multiple arrays. I'm using Swift 5.3 (Xcode 13.2.1)
struct ContainCharacterSelection {
var containNumbers: Bool = true
var containLowerCharacters: Bool = true
var containUpperCharacters: Bool = true
var containSpecialCharacters: Bool = true
var containComplicatedCharacters: Bool = false
}
class PasswordGenerator {
let numbers = ["0","1","2","3","4","5","6","7","8","9"]
let lowerCharacters = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
let upperCharacters = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]
let specialCharacters = ["!","\"","§","$","%","&","/","(",")","=","?","+","*","#",",",";",".",":","-","_","#","<",">"]
let complicatedCharacters = ["^","[","]","{","}","\\","'","`","´"]
var password = ""
var passwordLenght = sliderValue
}
Thanks in advance.
Join an array of strings into a single string.
let numbers = ["0","1","2","3","4","5","6","7","8","9"]
let joinedNumbers = array.joined() //joinedNumbers equals to 0123456789
Join other arrays via the same way:
joinedLowerCharacters,joinedUpperCharacters.....
Then we concatenate these strings as a single string.
finalString = joinedNumbers+joinedLowerCharacters+joinedUpperCharacters+...
Now we could generate password using the finalString.
Something like this would work. This is relatively simple and does not actually check the existence of certain type of character. If you need to absolutely verify the existence of certain character type, you might have to do some weird recursion logic.
However, this should work in most of the simpler cases.
struct ContainCharacterSelection {
var containNumbers: Bool = true
var containLowerCharacters: Bool = true
var containUpperCharacters: Bool = true
var containSpecialCharacters: Bool = true
var containComplicatedCharacters: Bool = false
}
class PasswordGenerator {
let numbers = ["0","1","2","3","4","5","6","7","8","9"]
let lowerCharacters = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
let upperCharacters = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]
let specialCharacters = ["!","\"","§","$","%","&","/","(",")","=","?","+","*","#",",",";",".",":","-","_","#","<",">"]
let complicatedCharacters = ["^","[","]","{","}","\\","'","`","´"]
var password = ""
var passwordLength = 32
func generate(selections: ContainCharacterSelection) {
var includedChars: [String] = [];
if selections.containLowerCharacters {
includedChars += lowerCharacters;
}
if selections.containUpperCharacters {
includedChars += upperCharacters;
}
if selections.containNumbers {
includedChars += numbers;
}
if selections.containSpecialCharacters {
includedChars += specialCharacters
}
if selections.containComplicatedCharacters {
includedChars += complicatedCharacters
}
includedChars.shuffle()
// mind it that this could crash if your array is smaller than the passwordLength, in that case use alternative solution commented below
self.password = includedChars[..< passwordLength].joined(separator: "")
// let randoms = (0 ..< passwordLength)
// .map { _ in includedChars.randomElement() }
// .compactMap { $0 }
// self.password = randoms.joined(separator: "")
}
}
var selections = ContainCharacterSelection()
selections.containUpperCharacters = true
selections.containLowerCharacters = true
selections.containSpecialCharacters = true
let passwordGenerator = PasswordGenerator()
passwordGenerator.generate(selections: selections)
print("Password: ", passwordGenerator.password)
I don't understand why I am failing to print out the properties of my realm result. when I print existingCart[i].${property}, it always give me a default value for all iteration i.
the statement print(existingCart) has no problem. It contains non default values in the properties. It returns:
Results<Product> <0x7fe5d8f3a770> (
[0] Product {
itemImage = <ffd8ffe0 00104a46 49460001 01000048 00480000 ffe10058 — 232200 total bytes>;
itemName = Ground Beef;
price = 6.53;
unit = 450 g;
quantity = 1;
isInCart = 0;
},
[1] Product {
itemImage = <ffd8ffe0 00104a46 49460001 01000048 00480000 ffe1004c — 153015 total bytes>;
itemName = Chicken Drumsticks;
price = 9.06;
unit = 1.25 kg;
quantity = 1;
isInCart = 0;
},
[2] Product {
itemImage = <ffd8ffe0 00104a46 49460001 01000048 00480000 ffe10058 — 242980 total bytes>;
itemName = Ground Turkey;
price = 6.91;
unit = 450 g;
quantity = 2;
isInCart = 0;
},
[3] Product {
itemImage = <ffd8ffe0 00104a46 49460001 01000048 00480000 ffe10058 — 224128 total bytes>;
itemName = Canned Beans;
price = 1.79;
unit = 398 mL;
quantity = 1;
isInCart = 0;
},
[4] Product {
itemImage = <ffd8ffe0 00104a46 49460001 01000048 00480000 ffe10058 — 252231 total bytes>;
itemName = Frosted Flakes;
price = 9.49;
unit = 1.06 kg;
quantity = 1;
isInCart = 0;
},
[5] Product {
itemImage = <ffd8ffe0 00104a46 49460001 01000048 00480000 ffe1004c — 165948 total bytes>;
itemName = Gouda Cheese;
price = 4.99;
unit = 300 g;
quantity = 1;
isInCart = 0;
}
)
This is how I try to load the data from Realm:
private func loadExistingCart() {
let realm = try! Realm()
let existingCart = realm.objects(Product.self)
print(existingCart) // see above
for i in 0..<existingCart.count {
print(existingCart[i].itemName) // empty string
print(existingCart[i].price) // 0.0
print(existingCart[i].quantity) // 0
print(existingCart[i].unit) // empty string
cart.addItem(existingCart[i]) // adds
}
}
Here is the product class:
import UIKit
import Foundation
import Realm
import RealmSwift
class Product : Object {
// MARK: Properties
#objc var itemImage = Data()
#objc var itemName: String = ""
#objc var price: Float = 0.0
#objc var unit: String = ""
#objc var quantity: Int = 0
#objc var isInCart: Bool = false
convenience init?(itemImage: UIImage?, itemName: String, price: Float, unit: String, quantity: Int, isInCart: Bool = false) {
self.init()
// itemName, unit, category should not be empty
guard (!itemName.isEmpty && !unit.isEmpty) else {
return nil
}
// price should not be a negative number
guard (price >= 0) else {
return nil
}
// Initialize stored properties
self.itemImage = UIImageJPEGRepresentation(itemImage!, 0.9)!
self.itemName = itemName
self.price = price
self.unit = unit
self.quantity = quantity
self.isInCart = isInCart
}
override class func primaryKey() -> String? {
return "itemName"
}
}
This is how products are being saved
private func saveToCart(product: Product, update: Bool) {
let realm = try! Realm()
print(product)
try! realm.write {
realm.add(product, update: true)
}
}
You've made a tiny error in the declaration of the Product class there, and it's just a common gotcha with using Realm.
If you look back over all the Realm examples in their documentation, you'll see that each member field should be declared such as this corrected one:
#objc dynamic var itemImage = Data()
Yep, you've missed out the dynamic modifier on each of your properties. Go back and add that to each property and it should just start working. For completeness, this should be the properties declaration:_
// MARK: Properties
#objc dynamic var itemImage = Data()
#objc dynamic var itemName: String = ""
#objc dynamic var price: Float = 0.0
#objc dynamic var unit: String = ""
#objc dynamic var quantity: Int = 0
#objc dynamic var isInCart: Bool = false
You can google the dynamic keyword for an explanation. It's based on the fact that the object you have is just a proxy to a database object, and Realm needs to intercept the property access to actually interrogate the database and retrieve the value of the property. You can see the same effect as your problem if you ever try to look at an object in the debugger - it's just full of the default values.
I'm not familiar enough with how Realm works to say why you can't seem to access the objects by index, but perhaps you could try accessing them as part of a Sequence instead?
let existingCart = realm.objects(Product.self)
for item in existingCart {
print(item.itemName)
print(item.price)
print(item.quantity)
print(item.unit)
}
Any ideas why this filter is not working correctly ?
for item in activeItems {
print("item.product: \(item.product), \(item.spaceRequired)")
}
returns
item.product: nil, 40.0
Filtering where product is nil
let f1 = activeItems.filter{$0.product != nil}
print("f1: \(f1)")
print("f1.count: \(f1.count)")
returns a count of ZERO but the array still appears to contain an item
f1: LazyFilterSequence<Results<AssortmentItem>>(_base: Results<AssortmentItem> <0x109ce2c90> (
[0] AssortmentItem {
...
f1.count: 0
And then filtering and mapping just spaceRequired
let f11 = f1.filter{$0.product!.isProduct == true}.map({$0.spaceRequired})
print("f11: \(f11)")
returns the same array with a single item
f11: LazyMapSequence<LazyFilterSequence<Results<AssortmentItem>>, Double>(_base: Swift.LazyFilterSequence<RealmSwift.Results<Merchandise_Manager.AssortmentItem>>(_base: Results<AssortmentItem> <0x109ce2c90> (
[0] AssortmentItem {
And then trying to reduce crashes
let w = f11.reduce(0,+)
This seems to fix the problem
let width = Array(activeItems.filter{$0.product != nil}).filter{$0.product!.isProduct == true}.map({$0.spaceRequired}).reduce(0,+)
Is this a bug in Swift 5 or in Realm ?
EDIT: It looks like this is a bug in Realm's handling of things.
To be a bit cleared below is a more complete set of the Realm objects.
import Foundation
import RealmSwift
let activeDate: NSDate = Date() as NSDate
let defaultWidth: Double = 40.0
class MyObject: Object {
#objc dynamic var number: Int = 0
#objc dynamic var name: String?
let items = List<ChildObject>()
}
extension MyObject {
var activeItems: Results<ChildObject> {
let activeDate = activeDate // Some globally defined value
let active = items.filter("startDate <= %# && (endDate >= %# || endDate == nil)", activeDate, activeDate).sorted(byKeyPath: "number")
return active
}
/// Works Correctly
var totalWidth: Double {
let width = Array(activeItems.filter{$0.product != nil}).filter{$0.product!.isProduct == true}.map({$0.spaceRequired}).reduce(0,+)
let width2 = Array(activeItems.filter{$0.product == nil}.map({$0.spaceRequired})).reduce(0,+)
return width+width2
}
/// Crashes
var totalWidth: Double {
let width = activeItems.filter{$0.product != nil}.filter{$0.product!.isProduct == true}.map({$0.spaceRequired}).reduce(0,+)
let width2 = activeItems.filter{$0.product == nil}.map({$0.spaceRequired}).reduce(0,+)
return width+width2
}
}
class ChildObject: Object {
#objc dynamic var parent: MyObject?
#objc dynamic var number: Int = 0
#objc dynamic var product: Product?
#objc dynamic var name: String?
#objc dynamic var spaceRequired: Double = 40.0
#objc dynamic var startDate: NSDate?
#objc dynamic var endDate: NSDate?
}
extension ChildObject {
var spaceRequired: Double {
if let p = product {
return p.width
} else {
return defaultWidth
}
}
}
class Product: Object {
#objc dynamic var isProduct: Bool = false
#objc dynamic var width: Double = 30.0
}
There's a couple of issues at work here but the main problem is that Realm Results are live updating; while you can filter data using the Swifty
let f1 = activeItems.filter{$0.product != nil}
it's going to give intermittent results since Realm doesn't know which items are filtered or not as .filter { is not a Realm function and Realm won't know what to update within the results.
You should generally use the built in Realm filtering mechanism
let results = realm.objects(ItemClass.self).filter("product != nil")
Those results will be live updating - if an object leaves the filter parameter, the results follow that. If an object matches the filter the results are updated as well.
I believe this Github issue #2138 provides some more light on the issue.
If you absolutely need static data, then I would suggest extending the Results class to return an array; like this
extension Results {
func toArray() -> [Element] {
return compactMap { $0 }
}
}
Keeping in mind this will use more memory as Realm objects are lazy loaded and and array isn't.
EDIT:
There's some additonal information in the question so I crafted up a simple example trying to replicate the issue. There's a HouseClass object which contains a List of RoomClass objects and then the HouseClass is extended to return the total width of all of the rooms in its list.
class RoomClass: Object {
#objc dynamic var room_name = ""
#objc dynamic var width = 0
#objc dynamic var length = 0
#objc dynamic var belongs_to_house: HouseClass!
}
class HouseClass: Object {
#objc dynamic var house_id = NSUUID().uuidString
#objc dynamic var house_name = ""
let rooms = List<RoomClass>()
override static func primaryKey() -> String? {
return "house_id"
}
}
extension HouseClass {
var totalWidth: Int {
let width = Array(rooms).map {$0.width}.reduce(0,+)
return width
}
var anotherTotalWidth: Int {
let width = rooms.map {$0.width}.reduce(0,+)
return width
}
}
and then the code to get all of the houses and output their room widths based on two different functions (see the HouseClass extension)
let houseResults = realm.objects(HouseClass.self)
for house in houseResults {
let w0 = house.totalWidth
print(w0)
let w1 = house.anotherTotalWidth
print(w1)
}
I added 100 houses each with three rooms and ran the above code several times without crash.
Count of f1 is 0 so map is not worked.
You can optimize your width calculation as following
let width = activeItems
.filter { $0.product?.isProduct ?? false }
.map { $0.spaceRequired }
.reduce(0,+)
I'm trying to get my head around swift & realm, so I've created some kind of a test pad programme.
My model is defined like so
class RealmRecord: Object {
// properties
dynamic var id: Int = 0;
dynamic var text: String = ""
dynamic var var1: Double = 0.0
dynamic var var2: Int = 0
dynamic var var3: Double = 0.0
dynamic var var4: Int = 0
dynamic var cdate: Date = Date()
dynamic var cusr: String = ""
dynamic var mdate: Date = Date.distantPast
dynamic var musr: String = ""
dynamic var mcnt: Int = 0
// methods
convenience init(id: Int? = 0, text: String? = "", var1: Double? = 0.0,
var2: Int? = 0, var3: Double? = 0.0, var4: Int? = 0,
cusr: String? = "") {
self.init()
self.id = id!
self.text = text!
self.var1 = var1!
self.var2 = var2!
self.var3 = var3!
self.var4 = var4!
self.cdate = Date()
self.cusr = cusr!
self.mdate = Date.distantPast
self.musr = ""
self.mcnt = 0
} // init
override static func primaryKey() -> String? {
return "id"
} // primaryKey
} // RealmRecord
Persisting the data is accomplished by
try recRealm?.write {
recRealm?.add(self.rec, update: true)
} // try
But when adding the data retrieval via
if let inrec = self.recRealm?.object(RealmRecord.self) {
return inrec
} else {
return List<RealmRecord>()
} // if/else
I'm receiving an error message while compiling the code, reading
DataRealmRecord.swift:84:39: Missing argument for parameter 'forPrimaryKey' in call
Looking at the Realm documentation reveals only retrieving all persisted data--apparently without having a primary key defined--, or, alternatively, a single object, specified by the primary key.
Sifting through The Net brings up pretty much the same.
Given the model above, how can I retrieve all persisted data?
-- Sil68
EDIT
I've also defined a class facilitating this Realm model of mine, which basically carries out the following steps:
generate some random data;
persist data via the Realm model;
read data in again;
compare generated with read data.
The code
import Foundation
import RealmSwift
class DataRealmRecord {
// properties
private(set) var recDBPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
private(set) var recDBSubPath = "Persistency"
private(set) var recDBFile = "data.realm"
private(set) var recRealm: Realm?
private(set) var recRealmCfg: Realm.Configuration?
private(set) var rec = List<RealmRecord>()
private(set) var startTime = 0.0
private(set) var stopTime = 0.0
private(set) var runTime = 0.0
private(set) var outLog = ""
private(set) var realmOk = false
// methods
init() {
// assemble destination folder/database name
do {
try FileManager.default.createDirectory(atPath: recDBPath + "/" +
recDBSubPath,
withIntermediateDirectories: true,
attributes: nil)
recDBFile = recDBPath + "/" + recDBSubPath + "/" + recDBFile
realmOk = true
} catch let error as NSError {
outLog += error.localizedDescription
realmOk = false
} // do/try/catch
// configure realm database
if (realmOk) {
self.recRealmCfg = Realm.Configuration(fileURL: Foundation.URL(string: self.recDBFile))
do {
self.recRealm = try Realm(configuration: self.recRealmCfg!)
realmOk = true
} catch let error as NSError {
outLog += error.localizedDescription
realmOk = false
} // do/try/catch
} // if
} // init
// generate test data
func generateData(noRecs: Int? = 1000, simDat: SimulateData?) {
for i in 1...noRecs! {
let realmRec = RealmRecord(id: i,
text: String(format: "Record #%04d", i),
var1: simDat?.datnorm[i - 1] ?? 1.1,
var2: simDat?.datpois[i - 1] ?? 2,
var3: simDat?.datunif[i - 1] ?? 3.3,
var4: simDat?.datbern[i - 1] ?? 4,
cusr: "me")
self.rec.append(realmRec)
} // for
} // generateData
// retrieve test data from persistent storage
func loadData() -> List<RealmRecord> {
if let inrec = self.recRealm?.object(RealmRecord.self) {
return inrec
} else {
return List<RealmRecord>()
} // if/else
} // loadData
// save test data to persistent storage
func saveData() {
do {
try recRealm?.write {
recRealm?.add(self.rec, update: true)
} // try
} catch let error as NSError {
outLog += error.localizedDescription
} // do/try/catch
} // saveData
// compare two data sets
func compareData(rec1: List<RealmRecord>, rec2: List<RealmRecord>) -> Bool {
var rc = false
if rec1.count == rec2.count {
rc = true
for i in 0..<rec1.count {
rc = rc && (rec1[i] == rec2[i])
} // for
} // if
return rc
} // compareData
// run a full evaluation cycle
// (1) generate test data;
// (2) save test data to persistant storage;
// (3) retrieve test data from persistant storage;
// (4) compare generated data with retrieved data.
func fullCycle(noRecs: Int? = 1000, simDat: SimulateData?, prnData: Bool? = false) {
// start execution time measurement
self.startTime = Double(CFAbsoluteTimeGetCurrent())
// execute the full cycle
self.generateData(noRecs: noRecs, simDat: simDat) // (1)
self.saveData() // (2)
let rec2 = self.loadData() // (3)
let cmpRec = compareData(rec1: self.rec, rec2: rec2) // (4)
// stop execution time measurement & calculate elapsed time
self.stopTime = Double(CFAbsoluteTimeGetCurrent())
self.runTime = self.stopTime - self.startTime
} // fullCycle
} // DataRealmRecord
Issue at hand is, this code fails to compile due to the error message mentioned above (in method loadData()).
The Swift compiler is telling you that it thinks you're trying to call Realm.object(ofType:forPrimaryKey:), which retrieves a single object based on the value of its primary key. It sounds like you really want to call Realm.objects(_:) to retrieve all objects of a given type. Note that this returns a Results<T>, not a List<T>.
I have defined my array in swift like
let cList = [[String]]()
now i want to fill the array with while getting response country code and country description.
So i can get it at the time of submit the page.
I am fetching my response below:
if let results = jsonResult["country"] as? NSArray
{
for country in results { {
let couCode: String? = country["couCode"] as? String
let couDescription: String? = country["couDescription"] as? String
println(couCode,couDescription)
self.countryList.append(couDescription!)
}
}
Now from above code how would i fill the two dimension array?
Is this what you're looking for?
var cList = [[String]]()
cList.append(["code1", "description1"])
cList.append(["code2", "description2"])
cList.append(["code3", "description3"])
cList.append(["code4", "description4"])
let towCode:String = "code4"
let towDescription:String = "description4"
for var i:Int = 0; i < cList.count; i++
{
if towCode == cList[i][0]
{
println("towCode found in cList at location \(i)")
println("towDescription at this location = \(cList[i][1])")
break;
}
}
for var i:Int = 0; i < cList.count; i++
{
if towDescription == cList[i][1]
{
println("towDescription found in cList at location \(i)")
println("towCode found at this location = \(cList[i][0])")
break;
}
}
Result:
towCode found in cList at location 3
towDescription at this location = description4
towDescription found in cList at location 3
towCode found at this location = code4
If you want to find multiple hits in cList, delete the break statements.
If I understand your situation, for a two dimensional array:
var cList = [[String]]()
cList.append(["String1", "String2"])
cList.append(["String3", "String4"])
println("cList = \(cList)")
println("cList[0][0] = \(cList[0][0])")
println("cList[0][1] = \(cList[0][1])")
Result:
cList = [[String1, String2], [String3, String4]]
cList[0][0] = String1
cList[0][1] = String2
or:
var cList = [[String]]()
cList.append(["String1", "String2", "String5"])
cList.append(["String3", "String4", "String6"])
println("cList = \(cList)")
println("cList[0][0] = \(cList[0][0])")
println("cList[0][1] = \(cList[0][1])")
println("cList[0][2] = \(cList[0][2])")
Result:
cList = [[String1, String2, String5], [String3, String4, String6]]
cList[0][0] = String1
cList[0][1] = String2
cList[0][2] = String5