Hi I am very new to programming and Swift and I am stuck with the search of the Address Book.
I get this error: _ABSearchComparison is not convertible to ABSearchComparison
var adbk = ABAddressBook.sharedAddressBook()
var isGroupBusiness = ABGroup.searchElementForProperty(kABGroupNameProperty, label: nil, key: nil, value: "Business", comparison: kABEqual)
thank you in advance
kABEqual has the type struct _ABSearchComparison and must therefore
by converted explicitly to an ABSearchComparison (aka CFIndex),
as expected by the comparison: parameter:
var isGroupBusiness = ABGroup.searchElementForProperty(kABGroupNameProperty,
label: nil, key: nil, value: "Business",
comparison: ABSearchComparison(kABEqual.rawValue))
Related
I have this class in a project which previously use swift 2.3. When i migrated the project to swift 3, xcode took forever to compile and i saw it stuck at this class. I can not build the whole project because of this class. Is there a way to modify this class so the project can be built, it took Xcode forever to compile this piece of code. If i removed several properties from MyClass, Xcode will quickly compile again. Anyone has any idea on how to solve this problem?
import Foundation
class MyClass: NSObject {
var id: String = ""
var uid: String = ""
var uname: String = ""
var fname: String = ""
var txt: String = ""
var hay: Float = 0
var flag = false
var long: Double = 0
var lat: Double = 0
var altitude: Double = 0
var course: Double = 0
var speed: Double = 0
var lname: String = ""
var city: String = ""
var country: String = ""
var sublocal: String = ""
var subarea: String = ""
var thumb: String = ""
var trash = false
var date: Double = 0
var updated: Double = 0
var furl: String = ""
func toAnyObject() -> Any {
return [
"id": id,
"uid": uid,
"uname": uname,
"fname": fname,
"txt": txt,
"hay": hay,
"flag": flag,
"long": long,
"lat": lat,
"altitude": altitude,
"course": course,
"speed": speed,
"lname": lname,
"city": city,
"country": country,
"sublocal": sublocal,
"trash": trash,
"subarea": subarea,
"thumb": thumb,
"date": date,
"updated": updated,
"furl": furl
]
}
}
Rewrite without the big dictionary literal. So:
func toAnyObject() -> Any {
var d = [String:Any]()
d["id"] = id
d["uid"] = uid
// ... and so on ...
return d
}
If you're not doing so already adding a -Xfrontend -debug-time-function-bodies compiler flag to your project will list the time required to compile each function. That can be a useful way to identify what exactly is slow in your build. (See http://irace.me/swift-profiling or https://thatthinginswift.com/debug-long-compile-times-swift/).
In your case the compiler is probably struggling to determine the type of your dictionary literal. Looking at each key and value and then trying to find the most appropriate common type for all of them. If you specified a type then I expect the compiler will only need to verify that your literal matches that type and compile much more quickly:
let result: [String: Any] = ["id": id, ...]
return result
Sometimes the compiler slows down when you do implicit typing. If you Explicitly add the type information then the compiler will not need to calculate it. I can see that the properties of your class mostly have type information but not all of them. In your toAnyObject method, it seems like you want your object represented as a dictionary, yet you are converting it to type Any.
You are making a dictionary literal and offering no type information. Explicitly casting with "as" can help a lot.
When you convert something to type Any, Objective-C interprets that as id. Normally a swift dictionary would be bridged to an NSDictionary for Objective-c, but you are forcing it to be of type Any. What reason would the compiler have to bridge this to an NSDictionary? It probably boxes it since it thinks it is a struct and objective-c can't use swift structs.
Try to not confuse the compiler.
I am writing an OS X app that should maintain a custom Keychain, I am trying to use the Security framework's API to create the Keychain, however, I can't seem to get it to compile under Swift.
Here's what I have, assume that path contains a path to a potentially existing Keychain:
let pathName = (path as NSString).UTF8String
var keychain: Unmanaged<SecKeychain>?
var status = withUnsafeMutablePointer(&keychain) { pointer in
SecKeychainOpen(pathName, pointer)
}
if status != errSecSuccess {
status = withUnsafeMutablePointer(&keychain) { pointer in
SecKeychainCreate(pathName, UInt32(0), nil, false, nil, pointer)
}
}
The compiler is complaining about the types in the SecKeychainCreate call, however, I fail to understand what am I doing wrong.
Cannot invoke 'withUnsafeMutablePointer' with an argument list of type '(inout Unmanaged<SecKeychain>?, (_) -> _)'
If I modify the second closure slightly, I get this compiler error:
Cannot invoke 'SecKeychainCreate' with an argument list of type '(UnsafePointer<Int8>, UInt32, nil, Bool, nil, (UnsafeMutablePointer<Unmanaged<SecKeychain>?>))'
I appreciate all suggestions.
The promptUser parameter of SecKeychainCreate() has the type
Boolean, which is a "Mac OS historic type" and an alias to UInt8,
so it is different from the Swift Bool in Swift 1.2.
(Compare Type 'Boolean' does not conform to protocol 'BooleanType' for a similar issue.)
This means that you have to
pass Boolean(0) instead of false:
SecKeychainCreate(pathName, UInt32(0), nil, Boolean(0), nil, pointer)
Additional remarks:
withUnsafeMutablePointer() is not needed, you can pass &keychain
to the keychain functions.
(path as NSString).UTF8String is not needed, you can pass a Swift
string to a C function expecting a const char * parameter,
compare String value to UnsafePointer<UInt8> function parameter behavior.
Passing nil as password to SecKeychainCreate() is only allowed
if promptUser is TRUE, otherwise it causes a
"parameter error (-50)".
SecKeychainOpen() succeeds even if the keychain file does not
exists. According to the documentation, you have to check
SecKeychainGetStatus(). Alternatively, you can try to create
the keychain file first, as for example in Open Local Items Keychain?.
Together:
let path = "/path/to/my.keychain"
var keychain: Unmanaged<SecKeychain>?
var status = SecKeychainCreate(path, 0, "", Boolean(0), nil, &keychain)
if status == OSStatus(errSecDuplicateKeychain) {
status = SecKeychainOpen(path, &keychain)
}
As of Swift 2 / Xcode 7 beta 5, the Mac type Boolean is mapped
to Swift as Bool, and the key chain functions do no longer return
unmanaged objects:
let path = "/path/to/my.keychain"
var keychain: SecKeychain?
var status = SecKeychainCreate(path, 0, "", false, nil, &keychain)
if status == OSStatus(errSecDuplicateKeychain) {
status = SecKeychainOpen(path, &keychain)
}
In the course of answering another question, I came across a weird bug in Playground. I have the following code to test if an object is an Array, Dictionary or a Set:
import Foundation
func isCollectionType(value : AnyObject) -> Bool {
let object = value as! NSObject
return object.isKindOfClass(NSArray)
|| object.isKindOfClass(NSDictionary)
|| object.isKindOfClass(NSSet)
}
var arrayOfInt = [1, 2, 3]
var dictionary = ["name": "john", "age": "30"]
var anInt = 42
var aString = "Hello world"
println(isCollectionType(arrayOfInt)) // true
println(isCollectionType(dictionary)) // true
println(isCollectionType(anInt)) // false
println(isCollectionType(aString)) // false
The code worked as expected when I put it into a Swift project or running it from the command line. However Playground wouldn't compile and give me the following error on the downcast to NSObject:
Playground execution failed: Execution was interrupted, reason: EXC_BAD_ACCESS (code=2, address=0x7fb1d0f77fe8).
* thread #1: tid = 0x298023, 0x00007fb1d0f77fe8, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x7fb1d0f77fe8)
* frame #0: 0x00007fb1d0f77fe8
frame #1: 0x000000010ba46e12 libswiftCore.dylib`Swift._EmptyArrayStorage._withVerbatimBridgedUnsafeBuffer (Swift._EmptyArrayStorage)<A>((Swift.UnsafeBufferPointer<Swift.AnyObject>) -> A) -> Swift.Optional<A> + 50
The build platform was OS X in all three cases. Does anyone know how to get Playground to play along?
Xcode 6.3.2. Swift 1.2. OS X 10.10.3 Yosemite
Not really the cause of that bug (it does look weird) but...
You will need to use optional chaining since value can be AnyObject:
import Foundation
func isCollectionType(value : AnyObject) -> Bool {
if let object = value as? NSObject {
return object.isKindOfClass(NSArray)
|| object.isKindOfClass(NSDictionary)
|| object.isKindOfClass(NSSet)
}
return false
}
var arrayOfInt = [1, 2, 3]
var dictionary = ["name": "john", "age": "30"]
var anInt = 42
var aString = "Hello world"
isCollectionType(arrayOfInt)
isCollectionType(dictionary)
isCollectionType(anInt)
isCollectionType(aString)
Also worth noting, NSArray and Array are different things:
NSArray is an immutable class:
#interface NSArray : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration>
whilst Array is a struct:
struct Array<T> : MutableCollectionType, Sliceable, _DestructorSafeContainer
With this in mind it might be surprising that isCollectionType(arrayOfInt) returns true - but there is a conversion happening.
I've been looking for some help in creating authorization for my app to have it run a few shell scripts as root. I've looked through the Apple documentation (which is of course written in OBJ-C and quite vague) and I'm trying to use the code examples in Swift.
Immediately I'm running in an error with the AuthorizationCreate function:
var authRef: AuthorizationRef
let osStatus = AuthorizationCreate(nil, nil, kAuthorizationFlagDefaults, &authRef)
'Int' is not convertible to 'AuthorizationFlags'
I'm just trying to follow along with the code snippets in the docs from: https://developer.apple.com/library/mac/documentation/Security/Conceptual/authorization_concepts/03authtasks/authtasks.html#//apple_ref/doc/uid/TP30000995-CH206-TP9
And I found the constant for kAuthorizationFlagDefaults from here: https://developer.apple.com/library/mac/documentation/Security/Reference/authorization_ref/#//apple_ref/doc/constant_group/Authorization_Options
I'm running in 10.10.1 if that matters.
I've seen the solution for using AppleScript, but I really want to avoid this is possible.
kAuthorizationFlagDefaults is an Int and has to be converted to
AuthorizationFlags (which is a type alias for UInt32). Also authRef has to be initialized:
var authRef: AuthorizationRef = nil
let authFlags = AuthorizationFlags(kAuthorizationFlagDefaults)
let osStatus = AuthorizationCreate(nil, nil, authFlags, &authRef)
Extended example (untested!):
var myItems = [
AuthorizationItem(name: "com.myOrganization.myProduct.myRight1",
valueLength: 0, value: nil, flags: 0),
AuthorizationItem(name: "com.myOrganization.myProduct.myRight2",
valueLength: 0, value: nil, flags: 0)
]
var myRights = AuthorizationRights(count: UInt32(myItems.count), items: &myItems)
let myFlags = AuthorizationFlags(kAuthorizationFlagDefaults |
kAuthorizationFlagInteractionAllowed |
kAuthorizationFlagExtendRights)
var authRef: AuthorizationRef = nil
let authFlags = AuthorizationFlags(kAuthorizationFlagDefaults)
let osStatus = AuthorizationCreate(&myRights, nil, authFlags, &authRef)
Edit: Swift 3
var myItems = [
AuthorizationItem(name: "com.myOrganization.myProduct.myRight1",
valueLength: 0, value: nil, flags: 0),
AuthorizationItem(name: "com.myOrganization.myProduct.myRight2",
valueLength: 0, value: nil, flags: 0)
]
var myRights = AuthorizationRights(count: UInt32(myItems.count), items: &myItems)
let myFlags : AuthorizationFlags = [.interactionAllowed, .extendRights]
var authRef: AuthorizationRef?
let osStatus = AuthorizationCreate(&myRights, nil, myFlags, &authRef)
Why is it that when I store words in an array like this I can't call just on one of the words that I stored. I'll give you an example of what I mean. This is an example of a game that I am working on. I'm doing this in Playground in Xcode using Swift.
var miamiHeat = ["james", "wade", "mario", "allen", "bosh"]
var questionOne = "Can you name one player from the miami heat?"
var answerToQuestionOne = ["james", "wade", "mario", "allen", "bosh"]
func testIfCorrect(answerToQuestionOne: String) -> String {
if miamiHeat == answerToQuestionOne {
println("The answer is correct")
} else {
println("The answer is incorrect")
}
return answerToQuestionOne
}
println(testIfCorrect("James"))
The only way that it will print "The answer is correct" is if I type in all the players name into the last println code. When I type in one of the players name into the println code it returns "The answer is incorrect." I only need to enter one of the names to get the answer correct.....so how would I do that? Thank you.
You are comparing a string with an array, not checking whether the string equals any of the strings within the array.
You need to loop through all the elements in the array, and check equality for each one.
Also, here println(testIfCorrect("James")), you have an uppercase "J", whereas in the array of names it is lowercase (the comparison is case sensitive).
I have amended your code:
var miamiHeat = ["james", "wade", "mario", "allen", "bosh"]
var questionOne = "Can you name one player from the miami heat?"
var answersToQuestionOne = ["james", "wade", "mario", "allen", "bosh"]
func testIfCorrect(answerToQuestionOne: String) -> String {
var correctAnswer: Bool = false
for answer in miamiHeat {
if answer == answerToQuestionOne {
correctAnswer = true
}
}
if correctAnswer {
println("The answer is correct")
} else {
println("The answer is incorrect")
}
return answerToQuestionOne
}
println(testIfCorrect("james"))
I believe the issue is because you are comparing the entire structure miamiheat with the answerToQuestionOne. To fix this you could add a switch statement to check each of the possible values of miamiheat. This website has few examples:
https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/GuidedTour.html