i'm new to swift and i have a problem. How i can save randomly generated for each user alphanumeric string in user defaults?
func randomString(of length: Int) -> String {
let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
var s = ""
for _ in 0 ..< length {
s.append(letters.randomElement()!)
}
return s
}
static var keyS: Bool {
get {
return ((UserDefaults.standard.integer(forKey: randomString(of: 16)) != 0))
}
set {
UserDefaults.standard.set(1, forKey: randomString(of: 16))
}
}
i tried this, but it didn't work. hope somebody can help me
Here "1" is your key for storing the random string. You can set it anything you want. Try this-
func randomString(of length: Int) -> String {
let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
var s = ""
for _ in 0 ..< length {
s.append(letters.randomElement()!)
}
return s
}
static var keyS: Bool {
get {
return ((UserDefaults.standard.integer(forKey: "1") != 0))
}
set {
UserDefaults.standard.set(randomString(of: 16), forKey: "1")
}
}
Related
I am getting data from different sources, the variable could be a number or a string of number. How do I make sure that "(number as? NSString)" or "(number as? NSNumber)" always success? Something similar to Java optInt, which will never fail even if the number is a String. See example below:
func testNumber()
{
var number = 123
guard let a = (number as? NSNumber)?.intValue else { print("1");return; }
}
func testNumberString()
{
var number = "123"
guard let a = (number as? NSNumber)?.intValue else { print("2");return; } // this failed.
}
func testNumberToString()
{
var number = 123
guard let a = (number as? NSString)?.intValue else { print("2");return; } // this sometimes failed too depend on datasource.
}
As I understand from your question, you want an integer value at the end, no matter if the input type is string or integer.
You can achieve this by using ExpressibleByStringLiteral.
Here is the demo
extension Int: ExpressibleByStringLiteral {
public typealias StringLiteralType = String
public init(stringLiteral value: StringLiteralType) {
self = Int(value) ?? 0
}
}
This Int extension allows you to accept string value as Int and return int value. If it did not convert it will give you 0 by default.
Example
func testInt() {
let numberOne: Int = "5656"
let numberTwo: Int = 1234
print(numberOne)
print(numberTwo)
}
Or another way is to create your own ExpressibleByStringLiteral, which helps you to give default value as you want.
struct StringInt: ExpressibleByStringLiteral {
var value: Int?
init(stringLiteral value: String) {
self.value = Int("\(value)")
}
func wrapped(with defaultValue: Int) -> Int {
return self.value ?? defaultValue
}
}
Example
func testInt() {
var numberThree: StringInt = "5656"
print(numberThree.value as Any) // with nil or optional value
numberThree = "asf"
print(numberThree.wrapped(with: 15)) // with default value
/**
Output
Optional(5656)
15
*/
}
How to implement successor() to Swift4, Swift5?
func withMask(mask: String) -> String {
var resultString = String()
let chars = self
let maskChars = mask
var stringIndex = chars.startIndex
var maskIndex = mask.startIndex
while stringIndex < chars.endIndex && maskIndex < maskChars.endIndex {
if (maskChars[maskIndex] == "#") {
resultString.append(chars[stringIndex])
stringIndex = stringIndex.successor()
} else {
resultString.append(maskChars[maskIndex])
}
maskIndex = maskIndex.successor()
}
return resultString
}
Value of type 'String.Index' has no member 'successor'
The Swift 3+ equivalent of successor() is index(after
stringIndex = chars.index(after: stringIndex)
This is all incredibly convoluted. Just user zip and map:
extension String {
func masked(using mask: String) -> String {
let newChars = zip(self, mask).map { sourceChar, maskChar in
return (maskChar == "#") ? "#" : sourceChar
}
return String(newChars)
}
}
Although using a String of characters, whose characters encode booleans (true if # otherwise false) probably isn't a great idea. Better to just use an IndexSet.
I have 2 similar computed properties like x & y
struct Window {
let defaults = UserDefaults.standard
var x: String {
get {
let x = defaults.string(forKey: "x")
return x ?? "3"
}
set {
defaults.set(newValue, forKey: "x")
}
}
var y: String {
get {
let y = defaults.string(forKey: "y")
return y ?? "10"
}
set {
defaults.set(newValue, forKey: "y")
}
}
}
And as x & y are doing the same thing, I want it to make it as a reusable function taking 2 different parameters, the forKey name like "x" & "y" & defaultValue like "2" or "3" in the above example.
I'm new to Swift & can't seem to figure it out if its possible or too easy. How should I do it?
struct Window {
let defaults = UserDefaults.standard
var x: String {
get {
return getValue(for:"x", defaultValue: "3")
}
set {
set(value: newValue, for:"x")
}
}
var y: String {
get {
return getValue(for:"y", defaultValue: "10")
}
set {
set(value: newValue, for:"y")
}
}
func getValue(for key:String, defaultValue:String) -> String {
let value = defaults.string(forKey: key)
return value ?? defaultValue
}
func set(value:String, for key:String) {
defaults.set(value, forKey:key)
}
}
Note that this approach used in your question and posted answers would not work for multiple objects. What you should do is extend UserDefaults and add a static property nested in a Window struct as follow:
extension UserDefaults {
struct Window { }
}
extension UserDefaults.Window {
static var x: CGFloat {
get {
return CGFloat(UserDefaults.standard.object(forKey: "Window.x") as? Double ?? 2.0)
}
set {
UserDefaults.standard.set(Double(newValue), forKey: "Window.x")
}
}
static var y: CGFloat {
get {
return CGFloat(UserDefaults.standard.object(forKey: "Window.y") as? Double ?? 3.0)
}
set {
UserDefaults.standard.set(Double(newValue), forKey: "Window.y")
}
}
}
Playground testing
UserDefaults.Window.x // 2 default value
UserDefaults.Window.x = 10
UserDefaults.Window.x // 10
A better approach (as already mentioned by #Sulthan in comments) would be merging x and y properties in a point (CGPoint) property
extension UserDefaults.Window {
static var point: CGPoint {
get {
guard let data = UserDefaults.standard.data(forKey: "Window.point") else { return CGPoint(x: 2, y: 3) }
return (NSKeyedUnarchiver.unarchiveObject(with: data) as? NSValue)?.cgPointValue ?? CGPoint(x: 2, y: 3)
}
set {
UserDefaults.standard.set(NSKeyedArchiver.archivedData(withRootObject: newValue), forKey: "Window.point")
}
}
}
Playground testing
UserDefaults.Window.point // {x 2 y 3} default value
UserDefaults.Window.point = .zero
UserDefaults.Window.point // {x 0 y 0}
I want the function to generate random String without repeating.
For example this function maybe will print: ABCC
func randomString(length:Int) -> String {
let charSet = "ABCDEF"
var c = charSet.characters.map { String($0) }
var s:String = ""
for _ in (1...length) {
s.append(c[Int(arc4random()) % c.count])
}
return s
} print(randomString(length: 4))
and i want print random unique string only, E.g : ABCD
import GameplayKit
func randomString(length : Int) -> String {
let charSet = Array("ABCDEFGHIJKLMNOPQRSTUVWXYZ".characters)
let shuffled = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: charSet) as! [Character]
let array = shuffled.prefix(length)
return String(array)
}
print(randomString(length: 4))
func randomString(length: Int) -> String {
let charSet = "ABCDEF"
var charSetArray = charSet.characters.map { String($0) }
var randArray: [String] = []
while charSetArray.count > 0 {
let i = Int(arc4random_uniform(UInt32(charSetArray.count)))
randArray.append(charSetArray[i])
charSetArray.remove(at: i)
}
var output: String = ""
for i in 0..<length {
output.append(randArray[i])
}
return output
}
How to use:
let randomString = "ABCDEF".random(length: 3)!
The return value is optional because the length might exceed the length of provided string.
Check out the full implementation:
import UIKit
import PlaygroundSupport
extension MutableCollection where Indices.Iterator.Element == Index {
mutating func shuffle() {
let c = count
guard c > 1 else { return }
for (firstUnshuffled , unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
let d: IndexDistance = numericCast(arc4random_uniform(numericCast(unshuffledCount)))
guard d != 0 else { continue }
let i = index(firstUnshuffled, offsetBy: d)
swap(&self[firstUnshuffled], &self[i])
}
}
}
extension Sequence {
func shuffled() -> [Iterator.Element] {
var result = Array(self)
result.shuffle()
return result
}
}
extension String {
func random(length: Int) -> String? {
let uniqueCharacters = Array(Set(characters.map({ String($0) })))
guard length <= uniqueCharacters.count else { return nil }
guard length > 0 else { return nil }
return uniqueCharacters[0..<length].shuffled().joined()
}
}
Does anyone know how to implement a NSTextField mask in Swift? Need to do a MAC address mask for it.
This should get you going.
class MacAddressFormatter : NSFormatter {
override func stringForObjectValue(obj: AnyObject?) -> String? {
if let string = obj as? String {
return string
}
return nil
}
override func getObjectValue(obj: AutoreleasingUnsafeMutablePointer<AnyObject?>, forString string: String, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>) -> Bool {
if obj != nil {
obj.memory = string
}
return true
}
override func isPartialStringValid(partialString: String, newEditingString newString: AutoreleasingUnsafeMutablePointer<NSString?>, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>) -> Bool {
if partialString.isEmpty { return true } //allow empty field
if partialString.characters.count > 17 { return false } //don't allow too many chars
let disallowedChars = NSCharacterSet(charactersInString: "0123456789ABCDEFabcdef:").invertedSet
if let _ = partialString.rangeOfCharacterFromSet(disallowedChars, options: .CaseInsensitiveSearch) {
error.memory = "Invalid entry. MAC Address can only contain 0-9 & A-F"
return false }
var string = ""
for char in partialString.characters {
if char != ":" {
string = string + String(char)
if string.characters.count % 3 == 0 {
string.insert(":", atIndex: string.endIndex.advancedBy(-1))
}
}
}
newString.memory = string.uppercaseString
return false
}
}
Just assign this formatter to you NSTextField and give it a try!