Swift Compare Set - facebook

I try to check FB permissions, like this:
let permissions = ["user_friends", "public_profile"];
NSLog("Contains Permissions:%#", FBSDKAccessToken.currentAccessToken()
.permissions);
NSLog("Requested Permissions:%#", permissions);
if(!FBSDKAccessToken.currentAccessToken().permissions.contains(permissions)){
return false;
}else{
return true;
}
But it always returns false. Anyone an idea why ?
EDIT: Log output
Contains Permissions:{(
"user_friends",
"public_profile"
)}
2015-10-28 23:01:59.723: Requested Permissions:(
"user_friends",
"public_profile"
)

The contains() function you've used checks to see of any element of 'current Access Token' permissions is an array of permissions. It is always false because the token permissions are strings, NOT arrays of strings.
If the two arrays need to have exactly the same elements, then the absolute simplest code would be:
let permissions = ["user_friends", "public_profile"];
NSLog("Contains Permissions:%#", FBSDKAccessToken.currentAccessToken()
.permissions);
NSLog("Requested Permissions:%#", permissions);
tokenPermissions = FBSDKAccessToken.currentAccessToken().permissions as? [String]
return tokenPermissions != nil && tokenPermissions.sort().elementsEqual(permissions.sort())
You might first object to using sort(), perhaps as overkill, but otherwise you will be traversing the two lists of permissions multiple time so sort() ends up not being such a concern.
Another option is to iterate over the tokenPermissions and ensure that every one is in permissions. Like such:
for tokenPermission in tokenPermissions {
if !permissions.contains (tokenPermission) {
return false
}
}
return true
Or, if you got really ambitious and need to do a lot of sequence testing:
extension SequenceType {
public func any (#noescape predicate: (Self.Generator.Element) -> Bool) -> Bool {
for elt in self {
if predicate (elt) { return true }
}
return false
}
public func all (#noescape predicate: (Self.Generator.Element) -> Bool) -> Bool {
for elt in self {
if !predicate (elt) { return false }
}
return true
}
}
and then your code contains:
return tokenPermissions.all { permissions.contains ($0) }
And, finally, if the two arrays of permissions are actually sets of permissions then you can use
return Set(tokenPermissions).elementsEqual(Set(permissions))
So you've got a bunch of options.

What you are probably looking for is
let permissions = ["user_friends", "public_profile"]
let tokenPermissions = FBSDKAccessToken.currentAccessToken().permissions
NSLog("Contains Permissions:%#", tokenPermissions)
NSLog("Requested Permissions:%#", permissions)
guard let tokenPermissions = tokenPermissions as? Set<String> else {
return false
}
return tokenPermissions.isSupersetOf(permissions)
For the isSupersetOf(_:) syntax see Swift Collection Types, you need to cast the untyped NSSet into a Swift Set<String> for the function to work.

You can change:
if(!FBSDKAccessToken.currentAccessToken().permissions.contains(permissions))
to:
if FBSDKAccessToken.currentAccessToken().permissions.containsObject("user_friends") && FBSDKAccessToken.currentAccessToken().permissions.containsObject("public_profile")
Solution for alot of set, see example code:
let permisssion = NSSet(array:["user_friends", "public_profile"])
let test = NSSet(array: ["user_friends", "email","public_profile"])
if permisssion.isSubsetOfSet(test as Set<NSObject>) {
print("true")
} else {
print("false")
}

Related

How to check the string doesn’t contain any letters in swift?

i have trouble during making the letter checker, my code is like this: if !containLetters(“1234h”){print(“pass”)}
my function is
func containsOnlyNum(input: String) -> Bool {
var ok = false
for chr in input {
for check in "1234567890.-"{
if chr == check{
ok = true
}
}
if ok != true{
return false
}
}
return true
}
If I check for “h” then didn’t pass, but if i check for ”1h” then it still pass! Please help me to fix this problem. I will give a big thank for anyone who helped me
The simplest way to fix the algorithm is this way:
func containsOnlyNum(input: String) -> Bool {
// check every character
for chr in input {
var isNum = false
for check in "1234567890.-"{
if chr == check {
isNum = true
// if we have found a valid one, we can break the iteration
break
}
}
if !isNum {
return false
}
}
return true
}
print(containsOnlyNum(input: "1234")) // true
print(containsOnlyNum(input: "1234h")) // false
However, then you can directly simplify it to:
func containsOnlyNum(input: String) -> Bool {
return input.allSatisfy { chr in
"1234567890.-".contains(chr)
}
}
which does exatly the same but uses allSatisfy and contains functions, which represent the logical operators ALL and EXISTS.
However, programmers normally use regular expressions for similar tasks:
func containsOnlyNum(input: String) -> Bool {
return input.range(of: "^[0-9.\\-]+$", options: .regularExpression) != nil
}
You can check that a string contains only the characters you're interested in like this:
extension String {
var containsOnlyNum: Bool {
let wanted = CharacterSet.decimalDigits
.union(CharacterSet(charactersIn: "-."))
return unicodeScalars
.allSatisfy(wanted.contains)
}
}
"-12.34".containsOnlyNum // true
"A1234".containsOnlyNum // false
But if you are interested in numbers, then this is a problem:
"-12.-34.".containsOnlyNum // true
Instead, you can just try casting the string to a double and see if it is a number or not
Double("1234") != nil // true, a number
Double("-1.234") != nil // true, a number
Double("A1234") != nil // false, not a number
Double("-12.-34.") != nil // false, not a number
Which is almost right unless you don't want this case:
Double("1234e2") != nil // true, a number
But you can use both checks if you don't want to allow that, or else if you are able to parse a Double from the input you can just do the cast.

Fetching all records from CloudKit using cursor recursive function - how to pass the result outside of its scope?

This may be tricky question so maybe someone here can help unless what I'm trying to do is forbidden by design.
So, I am fetching all the cloudkit records in packs to avoid 400 records limit. My function is:
func ck_queryAllStations(in_private:Bool) -> [CKRecord] {
var records = [CKRecord]()
let pred = NSPredicate(value: true)
let query = CKQuery(recordType:"RadioStation", predicate: pred)
let pDatabase:CKDatabase
if in_private == true {
pDatabase = CKContainer.default().privateCloudDatabase
} else {
pDatabase = CKContainer.default().publicCloudDatabase
}
let queryOperation = CKQueryOperation(query: query)
queryOperation.qualityOfService = .userInitiated
queryOperation.recordFetchedBlock = { record in
records.append(record)
print("rekord dopisany do tablicy\n")
}
queryOperation.queryCompletionBlock = { cursor,error in
if cursor != nil {
print("Jest Wiecej danych do pobrania - \(String(describing: cursor))")
self.fetchRecordsCloudKit(cursor: cursor!,in_private: in_private)
} else {
// print(self.records)
}
}
pDatabase.add(queryOperation)
return records
}
However,to achieve this I must use helper recursive function that is defined as below:
func fetchRecordsCloudKit(cursor:CKQueryOperation.Cursor?,in_private:Bool) {
print("Funkcja fetchRecordsCloudKit uruchomiona\n")
let pDatabase:CKDatabase
if in_private == true {
pDatabase = CKContainer.default().privateCloudDatabase
} else {
pDatabase = CKContainer.default().publicCloudDatabase
}
let queryoperation = CKQueryOperation(cursor: cursor!)
// queryoperation.qualityOfService = .userInitiated
queryoperation.recordFetchedBlock = { record in
records.append(record) // THIS LINE GIVES ERROR
print("rekord dopisany do tablicy")
}
queryoperation.queryCompletionBlock = { cursor,error in
if cursor != nil {
print("Wiecej danych do pobrania")
print(cursor as Any)
self.fetchRecordsCloudKit(cursor: cursor!,in_private: in_private)
}
}
pDatabase.add(queryoperation)
}
Problem is self.fetchRecordsCloudKit(cursor: cursor!,in_private: in_private) does not know anything about var records = [CKRecord]() variable.
If function is launch inside function, shouldn't it have access to all its variables the same way as class' method have acces to all class global variables?
I tried to pass records variable to recursive function as inout parameter, but apparently inout parameters in closures are forbidden since Swift 3.
So what to do? Is the only solution moving records array outside anything? In my mind that looks dirty hack to make array available globally BEFORE each asynchronous operation finish.

How to check if a string contains multiple characters in Swift 5

I have a failure initializer that takes a string, if this string contains incorrect characters (T, A, C, G) I want to return nil:
I tried something like this, unsuccessful:
init?(strand: String) {
let success = strand.contains(where: { !"TACG".contains($0) })
if !success {
return nil
}
self.strand = strand
}
I somehow got confused by the two contains calls, so I am not sure if my check is correct.
Any help is appreciated.
In this case I'd prefer the API rangeOfCharacter(from which checks the string against a character set
init?(strand: String) {
guard strand.rangeOfCharacter(from: CharacterSet(charactersIn: "TACG")) == nil else { return nil }
self.strand = strand
}
If you don't want to import Foundation you can also use Collection method allSatisfy
func allSatisfy(_ predicate: (Character) throws -> Bool) rethrows -> Bool
And make sure your string contains all characters
let allSatisfy = "CGAT".allSatisfy("TACG".contains)
print(allSatisfy) // true
Just move the ! placement, check out the code below .
init?(strand: String) {
let success = !strand.contains(where: { "TACG".contains($0) })
if !success {
return nil
}
self.strand = strand
}

Setting variable equal to if statement condition

I have an if statement that checks to see if an array element matches a local variable.
if pinArray.contains(where: {$0.title == restaurantName})
How would I create a variable of this element?
I attempted
let thePin = pinArray.contains(where: {$0.title == restaurantName})
but this comes with "could not cast boolean to MKAnnotation".
I also tried variations of
let pins = [pinArray.indexPath.row]
let pinn = pins(where: pin.title == restaurantName) (or close to it)
mapp.selectAnnotation(thePin as! MKAnnotation, animated: true)
to no avail. What basic step am I missing?
contains(where:) returns a Bool indicating whether a match was found or not. It does not return the matched value.
So thePin is a Bool which you then attempt to force-cast to a MKAnnotation which of course crashes.
If you want the matching value, change your code to:
if let thePin = pinArray.first(where: { $0.title == restaurantName }) {
do {
mapp.selectionAnnotation(thePin, animated: true)
} catch {
}
} else {
// no match in the array
}
No need for contains at all. No need to cast (assuming pinArray is an array of MKAnnotation).

How can you check if an object is one of an array of types?

Given the following array:
let ignoredViewControllerTypes:[UIViewController.Type] = [
ViewControllerB.self,
ViewControllerC.self
]
let allViewControllers = [
viewControllerAInstance,
viewControllerBInstance,
viewControllerCInstance,
viewControllerDInstance
]
What is the syntax to filter allViewControllers so that it excludes those types in ignoredViewControllerTypes?
I have tried this, but it doesn't work:
let filteredControllers = allViewControllers.filter{ !ignoredViewControllerTypes.contains($0.self) }
So what am I missing?
This should work:
let filteredControllers = allViewControllers.filter { viewController in
!ignoredViewControllerTypes.contains(where: { type(of: viewController) == $0 })
}
Let's break it down in subtasks:
you want to check if a controller should be allowed or not
func isAllowed(_ controller: UIViewController) -> Bool {
return !ignoredViewControllerTypes.contains { controller.isKind(of: $0) }
}
you want to filter an array of controllers:
let filteredControllers = allViewControllers.filter(isAllowed)
Note that isAllowed also filters subclasses of the ignored controllers, if you want exact type match then you should use #dan's answer.
As a bonus, and because I like functional programming, you can make isAllowed a pure and flexible function by converting it to a high-order function:
func doesntBelong(to prohibitedClasses: [AnyClass]) -> (AnyObject) -> Bool {
return { obj in
prohibitedClasses.contains { obj.isKind(of: $0) }
}
}
, which can be used like this:
let filteredControllers = allViewControllers.filter(doesntBelong(to: ignoredViewControllerTypes))