Swift 3 - How to declare an NSOrderedSet to use setVocabularyStrings? - ios

I want to use this function's prototype for adding vocabulary to SiriKit. Apple's documentation shows the following sample code:
let workoutNames = self.sortedWorkoutNames()
let vocabulary = INVocabulary.shared()
vocabulary.setVocabularyStrings(workoutNames, of: .workoutActivityName)
According to the documentation, I need to use an NSOrderedSet type for self.sortedWorkoutNames().
How to declare it and set it with an array of Strings?
EDIT: About the context project, I'm using Intents with Siri. The goal here, is to use specific word like 'Benchpress' or 'Chicken' just to start my workout app with an INStartWorkoutIntent already implemented and working like a charm.

If you look at Apple's sample code for SiriKit, you can tell that their function sortedWorkoutNames() returns an NSOrderedSet. Look at the type of workoutNames in the Objective-C version:
NSOrderedSet* workoutNames = [self sortedWorkoutNames];
In Swift that would be
let workoutNames: NSOrderedSet = self.sortedWorkoutNames()
If you have an array that you want to pass to INVocabulary.setVocabularyStrings(_:of:), you'd need to convert it to an ordered set. As #larme said in his comment, NSOrderedSet has an initializer that takes an array as input.
Your code might look like this:
let myVocab = ["Benchpress", "Squats", "Deadlift"]
let myVocabSet = NSOrderedSet(array: myVocab) //Convert myVocab to an NSOrderedSet
let vocabulary = INVocabulary.shared()
vocabulary.setVocabularyStrings(myVocabSet, of: .workoutActivityName)

Related

How to Store Levels Data

Im creating a game using SpriteKit but I’m not using sks files fore levels. I don’t to enter in details about the idea of the game before I release it but basically each level is auto generated based on a few numbers. So essentially what defines a level would be these numbers I would like to know where I could store this numbers. If I used sks files I would just have a file per level but in this case should I have them sorted in an array of levels? Should the array be in the level selection viewcontroller ? Should it be in a singleton class?
Basically what would be a good way to go about storing these values?
So the levels are auto-generated at runtime?
You could use an array of levels, or a file per level. I would just write them to one or more files in your app's documents directory. (I'd probably use one file per level, just to keep it simple and make it so you can easily add more levels without rewriting the whole game layout file each time.)
If you build your level structures out of scalar types, arrays, and dictionaries, (property list objects) then you can write the "object graph" to a property list using the NSArray or NSDictionary method write(to:).
Alternately you could make your level object conform to the Codable protocol, convert it to JSON, and save the JSON data to a file. The Codable protocol is easy to use, it's well documented by Apple, and there are tons of tutorials online.
EDIT
Note that you could also write your data to a property list using the Codable protocol. Just like the JSONEncoder and JSONDecoder classes, there are PropertyListEncoder and PropertyListDecoder classes that will convert your object graph back and forth to property list format. (Binary properties lists are more compact and faster to read and write than JSON.)
Below is a sample playground that defines a custom struct FooStruct, makes it Codable, and then uses a PropertyListEncoder to write the data to the playground's shared data directory (which you will have to set up if you want to test this code)
import UIKit
import PlaygroundSupport
struct FooStruct: Codable {
let aString: String
let anotherString: String
let anInt: Int
}
let fooArray: [FooStruct] = [FooStruct(aString: "Foo 1",
anotherString: "String 1", anInt: 4),
FooStruct(aString: "Foo 2",
anotherString: "String 2", anInt: 7)
]
let encoder = PropertyListEncoder()
encoder.outputFormat = .binary
do {
print(fooArray)
let data = try encoder.encode(fooArray)
let plistURL = playgroundSharedDataDirectory.appendingPathComponent("property list.plist")
try data.write(to: plistURL)
print("Data written to \(plistURL.path)")
} catch {
print (error)
}

In Swift or Objective-C, having a NSData object, is there a way to determine programmatically the NSData.ReadingOptions used to create it?

In Swift, let's consider this line of code:
let data = try Data.init(contentsOf: url, options:NSData.ReadingOptions.alwaysMapped)
Is there a chance, at a later stage, to retrieve programmatically the NSData.ReadingOptions value used to instantiate the object ? Thanks

How to get user sort order with CNContact API

I know that I can sort with CNContacts like this:
let fetch = CNContactFetchRequest(...)
fetch.sortOrder = .UserDefault
The question is: how do I find what is that sort order? Apart from some hacky heuristic of examining what comes back from the fetch enumeration.
There is an old ABPersonGetSortOrdering() call that will probably stay around for a while, but surely there is a CNContact way to do it.
ABPersonGetSortOrdering() was deprecated in iOS 9.0: use [[CNContactsUserDefaults sharedDefaults] sortOrder]
let sortOrder = CNContactsUserDefaults.sharedDefaults().sortOrder
Swift 4
Using the default sort Order :
let sortOrder = CNContactsUserDefaults.shared().sortOrder
For Custom Sort Order i.e.
let customSortOrder = CNContactSortOrder.givenName

PHAssetCollectionChangeRequest: addAssets() now accepts NSFastEnumeration. how to achieve this?

My Application tries to import an image from photos and adds to an album.
But in latest swift changes. addAssets() accepts parameter as NSFastEnumeration. So I get an error as shown in the image.
even the Apple API document has this same code: https://developer.apple.com/library/prerelease/ios/documentation/Photos/Reference/PHAssetChangeRequest_Class/index.html#//apple_ref/occ/instp/PHAssetChangeRequest/placeholderForCreatedAsset
What is the alternative or how do I addAssets now?
So, I did some research, and according to NSHipster, NSEnumeration is a protocol implemented by NSArray, NSSet, and NSDictionary. This suggests that if you convert [assetPlaceholder] to an NSArray, you'll be able to use it in the method. And, in fact, this compiles:
let enumeration: NSArray = [assetPlaceholder!]
albumChangeRequest!.addAssets(enumeration)

Swift - which types to use? NSString or String

With the introduction of Swift I've been trying to get my head round the new language
I'm an iOS developer and would use types such as NSString, NSInteger, NSDictionary in an application. I've noticed that in the "The Swift Programming Language" ebook by Apple, they use the Swift types String, Int, Dictionary
I've noticed the Swift types don't have (or are differently named) some of the functions that the Foundation types do. For example NSString has a length property. But I've not been able to find a similar one for the Swift String.
I'm wondering, for an iOS application should I still be using the Foundation types?
You should use the Swift native types whenever possible. The language is optimized to use them, and most of the functionality is bridged between the native types and the Foundation types.
While String and NSString are mostly interchangeable, i.e, you can pass String variables into methods that take NSString parameters and vice versa, some methods seem to not be automatically bridged as of this moment. See this answer for a discussion on how to get the a String's length and this answer for a discussion on using containsString() to check for substrings. (Disclaimer: I'm the author for both of these answers)
I haven't fully explored other data types, but I assume some version of what was stated above will also hold true for Array/NSArray, Dictionary/NSDictionary, and the various number types in Swift and NSNumber
Whenever you need to use one of the Foundation types, you can either use them to type variables/constants explicitly, as in var str: NSString = "An NSString" or use bridgeToObjectiveC() on an existing variable/constant of a Swift type, as in str.bridgeToObjectiveC().length for example. You can also cast a String to an NSString by using str as NSString.
However, the necessity for these techniques to explicitly use the Foundation types, or at least some of them, may be obsolete in the future, since from what is stated in the language reference, the String/NSString bridge, for example, should be completely seamless.
For a thorough discussion on the subject, refer to Using Swift with Cocoa and Objective-C: Working with Cocoa Data Types
NSString : Creates objects that resides in heap and always passed by reference.
String: Its a value type whenever we pass it , its passed by value.
like Struct and Enum, String itself a Struct in Swift.
public struct String {
// string implementation
}
But copy is not created when you pass. It creates copy when you first mutate it.
String is automatically bridged to Objective-C as NSString. If the Swift Standard Library does not have, you need import the Foundation framework to get access to methods defined by NSString.
Swift String is very powerful it has plethora of inbuilt functions.
Initialisation on String:
var emptyString = "" // Empty (Mutable)
let anotherString = String() // empty String immutable
let a = String(false) // from boolean: "false"
let d = String(5.999) // " Double "5.99"
let e = String(555) // " Int "555"
// New in Swift 4.2
let hexString = String(278, radix: 18, uppercase: true) // "F8"
create String from repeating values:
let repeatingString = String(repeating:"123", count:2) // "123123"
In Swift 4 -> Strings Are Collection Of Characters:
Now String is capable of performing all operations which anyone can
perform on Collection type.
For more information please refer apple documents.
Your best bet is to use Swift native types and classes, as some others have noted NSString has toll free translation to String, however, they're not the same a 100%, take for example the following
var nsstring: NSString = "\U0001F496"
var string: String = "\U0001F496"
nsstring.length
count(string)
you need to use the method count() to count the characters in string, also note that nsstring.length returns 2, because it counts its length based on UTF16.
Similar, YES
The same, NO
String and NSString are interchangeable, so it doesn't really matter which one you use. You can always cast between the two, using
let s = "hello" as NSString
or even
let s: NSString = "hello"
NSInteger is just an alias for an int or a long (depending on the architecture), so I'd just use Int.
NSDictionary is a different matter, since Dictionary is a completely separate implementation.
In general I'd stick to swift types whenever possibile and you can always convert between the two at need, using the bridgeToObjectiveC() method provided by swift classes.
Swift 4 update
String gets revisions in swift 4. Now you can directly call count on it and it consider grapheme clusters as 1 piece, like an emoji. NSString is not updated and is counting it in another way.
var nsstring: NSString = "πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘¦"
var string: String = "πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘¦"
print(nsstring.length) // 11
print(string.count) // 1
Since the objective C types are still dynamically dispatched they're probably going to be slower. I'd say you're best served using the Swift native types unless you need to interact with objective-c APIs
Use the Swift native types whenever you can. In the case of String, however, you have "seamless" access to all the NSString methods like this:
var greeting = "Hello!"
var len = (greeting as NSString).length
Swift Strings are quite elegant and easy to use, unless you need to parse them. The whole concept of indexing into Swift strings is just plain crazy. Whenever I need to parse through a typical unicode string, I convert it to NSString. Swift makes this a bit tricky though in that the common "character" integer expressions like ' ' or 'A' or '0' don't work in Swift. You have to use 32, 65, 48. Unfortunately, I'm not kidding! Because of this, I've put most of my string parsing code into an NSString extension written in Objective-C.
Yes I do know WHY Swift's designers made String indexing so crazy: They wanted to be able to express many-byte characters like emoji as single "Characters". My choice would have been to let this rare use case be expressed as multiple UTF16 characters, but what the heck.
String is a struct
// in Swift Module
public struct String
{
}
NSString is a class
// in Foundation Module
open class NSString : NSObject
{
}

Resources