NSTextField Mask (Swift 2.2) - swift

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!

Related

Realm accessed from incorrect thread occasional

I have this function
class func addCVals(_ criteres: [[AnyHashable: Any]], _ type: String) {
DispatchQueue.global(qos: .background).async {
autoreleasepool {
if criteres.count > 0 {
if let realm = DBTools.getRealm() {
do {
try realm.transaction {
let oldValues = CriteresVal.objects(in: realm, where: "type = '\(type)'")
if oldValues.count > 0 {
realm.deleteObjects(oldValues)
}
for critere in criteres {
let cval = CriteresVal(critere, type)
if let c = cval {
realm.addOrUpdate(c)
}
}
}
} catch {
DebugTools.record(error: error)
}
realm.invalidate()
}
}
}
}
}
The request that get oldValues occasionally cause an error
Realm accessed from incorrect thread
I don't understand why as I get a new Realm before with this lines:
if let realm = DBTools.getRealm()
My function getRealm:
class func getRealm() -> RLMRealm? {
if !AppPreference.lastAccount.elementsEqual("") {
let config = RLMRealmConfiguration.default()
do {
return try RLMRealm(configuration: config)
} catch {
DebugTools.record(error: error)
DispatchQueue.main.async {
Notifier.showNotification("", NSLocalizedString("UNKNOWN_ERROR_DB", comment: ""), .warning)
}
}
}
return nil
}
CriteresVal is an RLMObject that is composed of this:
#objcMembers
public class CriteresVal: RLMObject {
dynamic var cvalId: String?
dynamic var type: String?
dynamic var text: String?
dynamic var compositeKey: String?
override public class func primaryKey() -> String {
return "compositeKey"
}
private func updatePrimaryKey() {
self.compositeKey = "\(self.cvalId ?? "")/\(self.type ?? "")"
}
required init(_ cvalue: [AnyHashable: Any]?, _ type: String) {
super.init()
if let values = cvalue {
if let cvalId = values["id"] as? String {
self.cvalId = cvalId
} else if let cvalId = values["id"] as? Int {
self.cvalId = "\(cvalId)"
}
self.type = type
if let text = values["text"] as? String {
self.text = text
}
}
updatePrimaryKey()
}
func generateDico() -> [String: Any] {
var dicoSortie = [String: Any]()
if let realm = self.realm {
realm.refresh()
}
if let value = cvalId {
dicoSortie["id"] = value
}
if let value = type {
dicoSortie["type"] = value
}
if let value = text {
dicoSortie["text"] = value
}
return dicoSortie
}
}
compositeKey is the primary key which included cvalId and type
Thanks for help.

Swift4, successor()

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.

Convert to string an Any value

This fails (Non-nominal type 'Any' cannot be extended)
extension Any {
func literal() -> String {
if let booleanValue = (self as? Bool) {
return String(format: (booleanValue ? "true" : "false"))
}
else
if let intValue = (self as? Int) {
return String(format: "%d", intValue)
}
else
if let floatValue = (self as? Float) {
return String(format: "%f", floatValue)
}
else
if let doubleValue = (self as? Double) {
return String(format: "%f", doubleValue)
}
else
{
return String(format: "<%#>", self)
}
}
}
as I would like to use it in a dictionary (self) to xml string factory like
extension Dictionary {
// Return an XML string from the dictionary
func xmlString(withElement element: String, isFirstElement: Bool) -> String {
var xml = String.init()
if isFirstElement { xml.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n") }
xml.append(String(format: "<%#>\n", element))
for node in self.keys {
let value = self[node]
if let array: Array<Any> = (value as? Array<Any>) {
xml.append(array.xmlString(withElement: node as! String, isFirstElemenet: false))
}
else
if let dict: Dictionary<AnyHashable,Any> = (value as? Dictionary<AnyHashable,Any>) {
xml.append(dict.xmlString(withElement: node as! String, isFirstElement: false))
}
else
{
xml.append(String(format: "<%#>", node as! CVarArg))
xml.append((value as Any).literal
xml.append(String(format: "</%#>\n", node as! CVarArg))
}
}
xml.append(String(format: "</%#>\n", element))
return xml.replacingOccurrences(of: "&", with: "&amp", options: .literal, range: nil)
}
}
I was trying to reduce the code somehow, as the above snippet is repeated a few times in a prototype I'm building but this is not the way to do it (a working copy with the snippet replicated works but ugly?).
Basically I want to generate a literal for an Any value - previously fetched from a dictionary.
It seems like you can't add extensions to Any. You do have some other options though - either make it a function toLiteral(value: Any) -> String, or what is probably a neater solution; use the description: String attribute which is present on all types that conform to CustomStringConvertible, which includes String, Int, Bool, and Float - your code would be simplified down to just xml.append(value.description). You then just have make a simple implementation for any other types that you might get.
Ok, finally got this working. First the preliminaries: each of your objects needs to have a dictionary() method to marshal itself. Note: "k.###" are struct static constants - i.e., k.name is "name", etc. I have two objects, a PlayItem and a PlayList:
class PlayItem : NSObject {
var name : String = k.item
var link : URL = URL.init(string: "http://")!
var time : TimeInterval
var rank : Int
var rect : NSRect
var label: Bool
var hover: Bool
var alpha: Float
var trans: Int
var temp : String {
get {
return link.absoluteString
}
set (value) {
link = URL.init(string: value)!
}
}
func dictionary() -> Dictionary<String,Any> {
var dict = Dictionary<String,Any>()
dict[k.name] = name
dict[k.link] = link.absoluteString
dict[k.time] = time
dict[k.rank] = rank
dict[k.rect] = NSStringFromRect(rect)
dict[k.label] = label ? 1 : 0
dict[k.hover] = hover ? 1 : 0
dict[k.alpha] = alpha
dict[k.trans] = trans
return dict
}
}
class PlayList : NSObject {
var name : String = k.list
var list : Array <PlayItem> = Array()
func dictionary() -> Dictionary<String,Any> {
var dict = Dictionary<String,Any>()
var items: [Any] = Array()
for item in list {
items.append(item.dictionary())
}
dict[k.name] = name
dict[k.list] = items
return dict
}
}
Note any value so marshal has to be those legal types for a dictionary; it helps to have aliases so in the PlayItem a "temp" is the string version for the link url, and its getter/setter would translate.
When needed, like the writeRowsWith drag-n-drop tableview handler, I do this:
func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool {
if tableView == playlistTableView {
let objects: [PlayList] = playlistArrayController.arrangedObjects as! [PlayList]
var items: [PlayList] = [PlayList]()
var promises = [String]()
for index in rowIndexes {
let item = objects[index]
let dict = item.dictionary()
let promise = dict.xmlString(withElement: item.className, isFirstElement: true)
promises.append(promise)
items.append(item)
}
let data = NSKeyedArchiver.archivedData(withRootObject: items)
pboard.setPropertyList(data, forType: PlayList.className())
pboard.setPropertyList(promises, forType:NSFilesPromisePboardType)
pboard.writeObjects(promises as [NSPasteboardWriting])
}
else
{
let objects: [PlayItem] = playitemArrayController.arrangedObjects as! [PlayItem]
var items: [PlayItem] = [PlayItem]()
var promises = [String]()
for index in rowIndexes {
let item = objects[index]
let dict = item.dictionary()
let promise = dict.xmlString(withElement: item.className, isFirstElement: true)
promises.append(promise)
items.append(item)
}
let data = NSKeyedArchiver.archivedData(withRootObject: items)
pboard.setPropertyList(data, forType: PlayList.className())
pboard.setPropertyList(promises, forType:NSFilesPromisePboardType)
pboard.writeObjects(promises as [NSPasteboardWriting])
}
return true
}
What makes this happen are these xmlString extensions and the toLiteral function - as you cannot extend "Any":
func toLiteral(_ value: Any) -> String {
if let booleanValue = (value as? Bool) {
return String(format: (booleanValue ? "1" : "0"))
}
else
if let intValue = (value as? Int) {
return String(format: "%d", intValue)
}
else
if let floatValue = (value as? Float) {
return String(format: "%f", floatValue)
}
else
if let doubleValue = (value as? Double) {
return String(format: "%f", doubleValue)
}
else
if let stringValue = (value as? String) {
return stringValue
}
else
if let dictValue: Dictionary<AnyHashable,Any> = (value as? Dictionary<AnyHashable,Any>)
{
return dictValue.xmlString(withElement: "Dictionary", isFirstElement: false)
}
else
{
return ((value as AnyObject).description)
}
}
extension Array {
func xmlString(withElement element: String, isFirstElemenet: Bool) -> String {
var xml = String.init()
xml.append(String(format: "<%#>\n", element))
self.forEach { (value) in
if let array: Array<Any> = (value as? Array<Any>) {
xml.append(array.xmlString(withElement: "Array", isFirstElemenet: false))
}
else
if let dict: Dictionary<AnyHashable,Any> = (value as? Dictionary<AnyHashable,Any>) {
xml.append(dict.xmlString(withElement: "Dictionary", isFirstElement: false))
}
else
{
xml.append(toLiteral(value))
}
}
xml.append(String(format: "<%#>\n", element))
return xml
}
}
extension Dictionary {
// Return an XML string from the dictionary
func xmlString(withElement element: String, isFirstElement: Bool) -> String {
var xml = String.init()
if isFirstElement { xml.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n") }
xml.append(String(format: "<%#>\n", element))
for node in self.keys {
let value = self[node]
if let array: Array<Any> = (value as? Array<Any>) {
xml.append(array.xmlString(withElement: node as! String, isFirstElemenet: false))
}
else
if let dict: Dictionary<AnyHashable,Any> = (value as? Dictionary<AnyHashable,Any>) {
xml.append(dict.xmlString(withElement: node as! String, isFirstElement: false))
}
else
{
xml.append(String(format: "<%#>", node as! CVarArg))
xml.append(toLiteral(value as Any))
xml.append(String(format: "</%#>\n", node as! CVarArg))
}
}
xml.append(String(format: "</%#>\n", element))
return xml
}
func xmlHTMLString(withElement element: String, isFirstElement: Bool) -> String {
let xml = self.xmlString(withElement: element, isFirstElement: isFirstElement)
return xml.replacingOccurrences(of: "&", with: "&amp", options: .literal, range: nil)
}
}
This continues another's solution, the toLiteral() suggestion above, in hopes it helps others.
Enjoy.

Generate random String without repeating in swift

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()
}
}

Casting AnyObject to Specific Class

I'm using socket.io Swift Library. With the following line of code,
socket.on("info") { (dataArray, socketAck) -> Void in
let user = dataArray[0] as? User
print(user._id)
}
dataArray[0] is a valid object but user appears to be nil after casting.
Since dataArray[0] returns as an AnyObject,
how can i cast AnyObject to User Object?. Or somehow manage to do what i want with a different approach?
Since after this line
let user = dataArray[0] as? User
you have a nil value inside user it means that you don't have a User value at the first position of dataArray.
Since dataArray comes from a server (as I guess) it probably contains a serialized version of User.
Now we really need to know what really dataArray[0] is. However...
if dataArray[0] contains NSData
In this case try this
let json = JSON(dataArray[0] as! NSData)
let user = User(json:json)
You need to create a constructor that accept AnyObject and read data in it.
I guess in this case dataArray[0] is an JSON Object.
class User {
init(data: [String: AnyObject]) {
username = data["username"] as? String ?? ""
}
}
This is how i manage mine:
// Structure used as parameter
struct InfoStruct {
var nome: String = ""
var sobrenome:String = ""
var nascimentoTimestamp: NSNumber = 0
init() {
}
// Struct to AnyObject
func toAnyObject() -> Any {
var dic = [String:AnyObject?]()
if (nome != "") { dic["nome"] = nome as AnyObject }
if (sobrenome != "") { dic["sobrenome"] = sobrenome as AnyObject }
if (nascimentoTimestamp != 0) { dic["nascimentoTimestamp"] = nascimentoTimestamp as AnyObject }
return dic
}
// AnyObject to Struct
func fromAnyObject(dic:[String:AnyObject]) -> InfoStruct {
var retorno = InfoStruct()
if (dic["nome"] != nil) { retorno.nome = dic["nome"] as? String ?? "" }
if (dic["sobrenome"] != nil) { retorno.sobrenome = dic["sobrenome"] as? String ?? "" }
if (dic["nascimentoTimestamp"] != nil) { retorno.nascimentoTimestamp = dic["nascimentoTimestamp"] as? NSNumber ?? 0 }
return retorno
} }
// User class
class Usuario: NSObject {
var key: String
var admin: Bool
var info: InfoStruct // Struct parameter
init(_ key: String?) {
self.key = key ?? ""
admin = false
info = InfoStruct() // Initializing struct
}
// From Class to AnyObject
func toAnyObject() -> Any {
var dic = [String:AnyObject?]()
if (key != "") { dic["key"] = key as AnyObject }
if (admin != false) { dic["admin"] = admin as AnyObject }
dic["info"] = info.toAnyObject() as AnyObject // Struct
return dic
}
// From AnyObject to Class
func fromAnyObject(dic:[String:AnyObject]) -> Usuario {
let retorno = Usuario(dic["key"] as? String)
if (dic["key"] != nil) { retorno.key = dic["key"] as? String ?? "" }
if (dic["admin"] != nil) { retorno.admin = dic["admin"] as? Bool ?? false }
if (dic["info"] != nil) { retorno.info = InfoStruct.init().fromAnyObject(dic: dic["info"] as! [String : AnyObject]) } // Struct
return retorno
} }
// Using
let dao = FirebaseDAO.init(_type: FirebaseDAOType.firebaseDAOTypeUser)
dao.loadValue(key: uid) { (error, values:[String : AnyObject]) in
if error == nil {
let user = Usuario(values["key"] as? String).fromAnyObject(dic: values)
}
}
I hope it helps!