iOS unwrapping SystemSound - ios

I stored an Int in UserDefaults. The Int will serve as the index of audioOptionsList, an array of objects, each having a SystemSoundID property.
This crashes with error: Could not cast value of type 'NSTaggedPointerString' (0x7fff87b33c28) to 'NSNumber' (0x7fff87bf4e00).
var soundToPlay = SystemSoundID(1322)
override func viewDidLoad() {
super.viewDidLoad()
if UserDefaults.standard.value(forKey: "timerSoundSelection") != nil {
let storedIndex = UserDefaults.standard.value(forKey: "timerSoundSelection")!
print("stored index is: \(storedIndex)") //prints a non-optional int as expected.
soundToPlay = audioOptionsList[storedIndex as! Int].sound //crashes with error
} else {
soundToPlay = SystemSoundID(1322)
}

Your key is stored as a String not an Int , use string(forKey: then cast it
if let stored = UserDefaults.standard.string(forKey: "timerSoundSelection")
, let value = Int(stored) { }

Related

Swift Firebase - Contextual type 'AnyObject' cannot be used with dictionary literal

I'm getting this error which I can't figure out how to fix:
Contextual type 'AnyObject' cannot be used with dictionary literal
I've searched on the internet but failed to find an answer. Here's my code:
struct Sweet {
let key:String!
let content:String!
let addedByUser:String!
let itemReft:FIRDatabaseReference?
init (content:String, addedByUser:String, key:String = "") {
self.key = key
self.content = content
self.addedByUser = addedByUser
self.itemReft = nil
}
init (snapshot:FIRDataSnapshot) {
key = snapshot.key
itemReft = snapshot.ref
if let dict = snapshot.value as? NSDictionary, let postContent = dict["content"] as? String {
content = postContent
} else {
content = ""
}
if let dict = snapshot.value as? NSDictionary, let postUser = dict["addedByUser"] as? String {
addedByUser = postUser
} else {
addedByUser = ""
}
}
func toAnyObject() -> AnyObject {
return ["content":content, "addedByUser":addedByUser]
}
The error happens at this line:
return ["content":content, "addedByUser":addedByUser]
I've been following this tutorial iOS Swift Tutorial: Get started with Firebase and an App like Twitter
Thanks for your time!
You have to cast the literal to the desired type
func toAnyObject() -> Any {
return ["content":content, "addedByUser":addedByUser] as Any
}
But - no offense – casting up a specific type to something more unspecific is silly. Why not
func toDictionary() -> [String:String] {
return ["content":content, "addedByUser":addedByUser]
}

Cannot subscript a value of type '[Int : [String]]' with an index of type 'String!'

please, ask me, where is my mistake? I have Xcode error:
Cannot subscript a value of type '[Int : [String]]' with an index of
type 'String!'
in let keyExists = myDict[tmp.Hour] != nil, myDict[tmp.Hour] = Int and myDict[tmp.Hour].append(tmp.Minutes) of that part of code:
func array() -> Dictionary <Int,[String]>
{
let timeInfos = getTimeForEachBusStop()
var myDict: Dictionary = [Int:[String]]()
for tmp in timeInfos {
let keyExists = myDict[tmp.Hour] != nil
if (!keyExists) {
myDict[tmp.Hour] = [Int]()
}
myDict[tmp.Hour].append(tmp.Minutes)
}
return myDict
}
I understand, that problem is in optional type, but where is problem I don't understand
upd
func getTimeForEachBusStop() -> NSMutableArray {
sharedInstance.database!.open()
let lineId = getIdRoute
let position = getSelectedBusStop.row + 1
let getTimeBusStop: FMResultSet! = sharedInstance.database!.executeQuery("SELECT one.hour, one.minute FROM shedule AS one JOIN routetobusstop AS two ON one.busStop_id = (SELECT two.busStop_id WHERE two.line_id = ? AND two.position = ?) AND one.day = 1 AND one.line_id = ? ORDER BY one.position ASC ", withArgumentsInArray: [lineId, position, lineId])
let getBusStopInfo : NSMutableArray = NSMutableArray()
while getTimeBusStop.next() {
let stopInfo: TimeInfo = TimeInfo()
stopInfo.Hour = getTimeBusStop.stringForColumnIndex(0)
stopInfo.Minutes = getTimeBusStop.stringForColumnIndex(1)
getBusStopInfo.addObject(stopInfo)
}
sharedInstance.database!.close()
return getBusStopInfo
}
You are declaring your dictionary as a dictionary with keys of type Int and values of type [String]:
var myDict: Dictionary = [Int:[String]]()
(better written as: var myDict: [Int: [String]] = [:] because by casting it to Dictionary you are removing the types).
However, in
myDict[tmp.Hour] = [Int]()
You are using a value which is of [Int] type and tmp.Hour is probably a String.
So, your problem is a type mismatch.
The error states that you cannot subscribe your [Int:[String]] dictionary with a String key.
Therefore the type of tmp.Hour is obviously String rather than the expected Int
If tmp.Hour is guaranteed to be an integer string you can convert the value
let hour = Int(tmp.Hour)!
myDict[hour] = [Int]()
On the other hand since myDict is [Int:[String]] you might mean
let hour = Int(tmp.Hour)!
myDict[hour] = [String]()
Hour and Minutes are of type string (I guess - stringForColumnIndex) so your dictionary is wrong type. Should be:
func array() -> Dictionary <String,[String]>
{
let timeInfos = getTimeForEachBusStop()
var myDict: Dictionary = [String:[String]]()
for tmp in timeInfos {
let keyExists = myDict[tmp.Hour] != nil
if (!keyExists) {
myDict[tmp.Hour] = [String]()
}
myDict[tmp.Hour].append(tmp.Minutes)
}
return myDict
}

Could not cast value of type 'NSTaggedPointerString' to 'NSArray'

I have the following code in my Share Extension in didSelectPost:
let sharedDefaults = NSUserDefaults(suiteName: "group.appliaison.ActionExtensionSharingDefaults")
var urls: [String] = []
urls.append(self.contentText)
sharedDefaults?.setObject(urls, forKey: "stringKey")
and the following code in viewDidLoad in my main applications VC
var urls:[String] = []
override func viewDidLoad() {
super.viewDidLoad()
let sharedDefaults = NSUserDefaults(suiteName: "group.appliaison.ActionExtensionSharingDefaults")
urls = (sharedDefaults?.objectForKey("stringKey") as? [String])!
...
}
But when I run it, I get the following error :
Could not cast value of type 'NSTaggedPointerString' to 'NSArray'
stringKey is as String in sharedDefaults.you can check with
following code
if let item = sharedDefaults["stringKey"] {
if item is String {
print("I'm String -> \(item)")
} else if item is [String] {
print("I'm Arry -> \(item)")
}
}

How to save an array of strings using NSUserDefaults in swift

I am trying to save an string array using NSUserDefaults with swift. I have searched around and believe that i have to use [NSString] not [String] however the app still crashes with error
fatal error: unexpectedly found nil while unwrapping an Optional value
I can not see what i am doing wrong as it is working perfectly fine saving ints and strings. Here is my code for my data singleton and NSUserDefaults.
struct DefaultsKeys
{
static let myString = "myString"
static let myInt = "myInt"
static let myArray = "myArray"
}
class DataContainerSingleton
{
static let sharedDataContainer = DataContainerSingleton()
var myString: String?
var myInt: Int?
var myArray:[NSString]?
/* I have also tried:
var myArray:[NSString] = [NSString]() */
var goToBackgroundObserver: AnyObject?
init()
{
let defaults = NSUserDefaults.standardUserDefaults()
myString = defaults.objectForKey(DefaultsKeys.myString) as! String?
myInt = defaults.objectForKey(DefaultsKeys.myInt) as! Int?
myArray = defaults.objectForKey(DefaultsKeys.myArray) as! [NSString]?
goToBackgroundObserver = NSNotificationCenter.defaultCenter().addObserverForName(
UIApplicationDidEnterBackgroundNotification,
object: nil,
queue: nil)
{
(note: NSNotification!) -> Void in
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject( self.myString, forKey: DefaultsKeys.my)
defaults.setObject( self.myInt, forKey: DefaultsKeys.myInt)
defaults.setObject( self.myArray, forKey: DefaultsKeys.myArray)
defaults.synchronize()
}
}
}
<!-- language: swift -->
//declare and initiate the array
var sample_array : NSMutableArray! = []
//use mutable array to add data
//variable to store value in array
var say: String! = "Hello"
//add values in array
sample_array.addObject("hello")
//or
//sample_array.addObject(say)
/*
//you can also save values in array like this
var sample_array: Array<String> = []
var say: String! = "Hello"
sample_array = ["Qwerty"]
sample_array.insert(say, atIndex: 1)
println(sample_array)
*/
//archive and saving data
let data = NSKeyedArchiver.archivedDataWithRootObject(sample_array)
NSUserDefaults.standardUserDefaults().setObject(data, forKey: "array_key")
NSUserDefaults.standardUserDefaults().synchronize()
//unarchive and getting data
if let data = NSUserDefaults.standardUserDefaults().objectForKey("array_key") as? NSData {
stopover_array = NSKeyedUnarchiver.unarchiveObjectWithData(data) as NSMutableArray
}
Problem is the code:
myString = defaults.objectForKey(DefaultsKeys.myInt) as! String?
myInt = defaults.objectForKey(DefaultsKeys.myInt) as! Int?
myArray = defaults.objectForKey(DefaultsKeys.myArray) as! [NSString]?
as! means unwraping an optional value, that's why your app crashed with error
fatal error: unexpectedly found nil while unwrapping an Optional value
if defaults.objectForKey(DefaultsKeys.myInt) is nil, then unwrapping nil is not allowed. You should use
myString = defaults.objectForKey(DefaultsKeys.myInt) as? String
instead.

NSURL getResourceValue in swift

Having trouble figuring out how to make the following call in swift:
var anyError: NSError? = nil
var rsrc: NSNumber? = nil
var success = url.getResourceValue(&rsrc, forKey:NSURLIsUbiquitousItemKey, error:&anyError)
The above does not compile:
Cannot convert the expression's type 'Bool' to type 'inout Bool'
So I tried this:
var anyError: NSError? = nil
var rsrc: AutoreleasingUnsafePointer<AnyObject?> = nil
var success = url.getResourceValue(rsrc, forKey:NSURLIsUbiquitousItemKey, error:&anyError)
but this generates EXC_BAD_ACCESS runtime error.
How do I pass in the expected first arg as AutoreleasingUnsafePointer<AnyObject?> (which should point to a boolean NSNumber according to doc), and then be able to check its expected Bool value ?
You need to make rsrc an optional AnyObject and pass it by reference like so:
var anyError: NSError?
var rsrc: AnyObject?
var success = url.getResourceValue(&rsrc, forKey:NSURLIsUbiquitousItemKey, error:&anyError)
Note: You do not need to initialize Optionals to nil, they are set to nil by default.
If you then want to check if the value is an NSNumber you can then do a conversion:
if let number = rsrc as? NSNumber {
// use number
}
Here is drewag's code updated for Swift 2.0
do {
var rsrc: AnyObject?
try element.getResourceValue(&rsrc, forKey: NSURLIsDirectoryKey)
if let number = rsrc as? NSNumber {
if number == true {
// do something
}
}
} catch {
}
in swift 3 previous calls are not available/deprecated:
so use:
var keys = Set<URLResourceKey>()
keys.insert(URLResourceKey.isDirectoryKey)
do{
let URLResourceValues = try fileURL.resourceValues(forKeys: keys)
}catch _{
}
If the getResourceValue(:forKey:) result is ultimately a logical value, you can cast the returned pointer value directly to a Bool value:
let boolResult = rsrc as! Bool
or simply test it as a Bool value without assigning it:
if rsrc as! Bool {
// true code
} else {
// false code
}
or do both:
if let rsrc as! Bool {
// true
} else {
// false
}
Here's a concrete example as an extension of the URL type:
extension URL {
var creationDate : Date {
let url = self as NSURL
var value : AnyObject?
try? url.getResourceValue(&value, forKey: .creationDateKey)
if let date = value as? Date {
return date
}
return .distantPast
}
}
For convenience, if the call to getResourceValue() fails, it returns the value .distantPast by default. Using the try? form allows discarding the error which isn't always needed.

Resources