Just updated to Xcode 12.0 from the last version of Xcode 11/iOS13 and am getting an error in AppDelegate: Thread 1: "Subclass MPMediaItem must implement -valueForProperty: defined in [MPMediaItem class]."
When the app starts, I MPMediaQuery the library for songs and store them to a #Published variable in an Observable Object like this:
#Published var songs = [MPMediaItem]()
init() {
self.songs = MPMediaQuery.songs().items
}
Later when I want to access a property I do so like this:
Text(self.observableObject.songs[0].title)
I’ve tried changing these to use .value(forProperty: "MPMediaItemPropertyTitle") but it doesn’t feel to be use a string over a property (and Xcode then pops up errors like Failed to produce diagnostic for expression; please file a bug report apple.) AFAIK, I’m not subclassing MPMediaItem anywhere and I’ve tried Googling the error above with no luck.
Anyone know what’s going on?
I'm not sure if this is useful to your situation, but I recently came across a simiar problem.
In my case I needed to change 2 things that triggered this crash:
I was initialising an empty MPMediaItem() as placeholder when no current song was loaded. The crash happened when trying to access a property (e.g. title) on this empty instance. Upon removing the empty MPMediaItem() and implementing a different placeholder approach, the problem went away.
To test music on the simlator I was using a DummyMediaQuery: MPMediaQuery which returned an array of DummyMediaItem: MPMediaItem. In the DummyMediaItem class I did:
final class DummyMediaItem: MPMediaItem {
private let _artist: String
override var artist: String { return _artist }
private let _title: String
override var title: String { return _title }
// and so on...
// fix: crash in iOS 14
override func value(forProperty property: String) -> Any? {
return nil
}
}
I'm working with the parse framework for an App that I'm converting to Xcode 7. One of the interesting errors which has occurred as part of migrating the project is the following:
Cast from 'MDLMaterialProperty?!' to unrelated type 'PFUser' always fails
The offending line seems to be the "if let" clause below. I've commented the old line which worked fine in the previous version of Swift for comparison.
With respect to what this is actually doing - I've passed an array of Parse objects into "likesForThankful" where a pointer "userID" refers to a related PFUser. As part of this method I'm writing individual PFUsers to an array.
Any help is appreciated - thanks in advance.
//Add PFUsers who Like Post to our FeedItem
private func callbackFromLikesProcessing(likesForThankful:[AnyObject], againstFeedItem:FeedItem){
//Instantiate our Objective C compatible array for processing later
againstFeedItem.parseUsersObjectsWhoLikePost = NSMutableArray()
//Loop through likes and add PFUsers to array of users who like post
for usersWhoLikePost in likesForThankful{
// if let parseUserWhoLikesPost = usersWhoLikePost["userID"] as PFUser{
if let parseUserWhoLikesPost = usersWhoLikePost["userID"] as? PFUser {
againstFeedItem.parseUsersObjectsWhoLikePost.addObject(parseUserWhoLikesPost)
}
}
Andrew
Figured this out if it can help anyone - it's basic Swift Syntax (though I'm not sure why the compiler let me get away with this in the first version of Swift!).
Because usersWhoLikePost is a PFObject which happens to contain a pointer to a PFUser object I needed to conditionally unwrap this first like so:
for usersWhoLikePost in likesForThankful{
if let parseLikeObject = usersWhoLikePost as? PFObject{
if let parseUserWhoLikesPost = parseLikeObject["userID"] as? PFUser {
againstFeedItem.parseUsersObjectsWhoLikePost.addObject(parseUserWhoLikesPost)
}
}
}
After this I could continue as I had previously done and access the "userID" property with a conditional unwrap of the PFUser object.
I am trying to use Realm for my iOS app. When updating the local Realm DB using createOrUpate, it rewrites the unprovided properties with default values, rather than keep them unchanged. The Realm I use is up to date, 0.93. Anybody has the same issue?
let realm = RLMRealm.defaultRealm()
realm.beginWriteTransaction()
for matchedUser in matchedUsers {
let newMatchedUser = MatchedUser()
newMatchedUser.objectId = matchedUser.objectId
newMatchedUser.username = matchedUser.username
newMatchedUser.email = matchedUser.email
newMatchedUser.fullname = matchedUser["fullname"] as! String
//they are other properties unprovided here.
MatchedUser.createOrUpdateInDefaultRealmWithValue(newMatchedUser)
}
realm.commitWriteTransaction()
So, I figured out what the issue was. It turns out you cannot user newMachtedUser to update the DB because it will initialize it first and the default values will be provided for this initialization process. The right way is to using individual values to update, or create an dictionary/array for that update.
I want to know how to create a dictionary of [String:AnyObject] from an UnsafePointer<AudioStreamBasicDescription>
I guess I don't understand how to work with an UnsafePointer<T> in Swift. Here's where I'm starting from - The AVAudioFile class has a fileFormat property which is of AVAudioFormat Type. AVAudioFormat has a streamDescription property which returns an UnsafePointer<AudioStreamBasicDescription> as a read-only property.
I'd like to see what the values are in this struct and converting to a Dictionary seems like it might be reasonable goal. In fact, there already seems to be a "settings" property on the AVAudioFormat Class that does this but I'm interested in understanding the "right way" to access the values stored in the UnsafePointer myself.
From the docs
Discussion: Returns the AudioStreamBasicDescription (ASBD) struct, for use with lower-level audio APIs
https://developer.apple.com/library/prerelease/ios/documentation/AVFoundation/Reference/AVAudioFormat_Class/index.html
Is there a way to do an unsafe conversion after checking if the struct is not nil? Would I use an unsafeBitCast here? I'm hesitant to jump into this too much as I've read that it's "extremely dangerous"...
I realize I can access the underlying memory with the following:
let audioFileURL:NSURL = NSBundle.mainBundle().URLForResource("FILENAME", with Extension: "mp3")
var file:AVAudioFile?
do {
file = try AVAudioFile(forReading: audioFileURL)
guard let file = file else {
fatalError("file must not be nil")
}
}catch {
print(error)
}
let format = file.processingFormat
let asbd:AudioStreamBasicDescription = format.streamDescription.memory
Is that dangerous and would I need to dealloc for some reason after creating the asbd constant?
I've tried to follow along with the post here http://sitepoint.com/using-legacy-c-apis-swift but I'm just not getting it... Looking for any direction on best practices here.
Update:
Doing a bit more research, it seems that it might be possible to create the dictionary using reflect based off this post: http://freecake.angelodipaolo.org/simple-reflection-in-swift/
Here's what I have so far:
let asbdMirror = reflect(asbd)
var asbdDict = [String: Any]()
for i in 0..<asbdMirror.count {
let (propertyName, childMirror) = asbdMirror[i]
asbdDict[propertyName] = childMirror.value
}
Any reason this is a bad idea?
You are doing everything correctly, you can access all the values in the description with asbd.mSampleRate and such. It wouldn't make sense to convert it to a dictionary because that's just not what it is, there are no keys for the values.
You also don't have to dealloc anything when working with pointers like this unless you allocate one yourself (when using malloc or alloc)
I have a little strange issue which I can't seem to figure out, I have a simple entity with a custom NSManagedObject subclass:
#objc(EntityTest) class EntityTest: NSManagedObject {
#NSManaged var crDate: NSDate
#NSManaged var name: String
#NSManaged var completed: Bool
#NSManaged var completedOn: NSDate
}
This is the problem, I can create the object fine and set the all the values and store in in an array. However late on, when I try to retrieve the same object, I can set all the values EXCEPT the "completed" field. I get a run-time error saying "EXC_BAD_ACCESS", I can read the value, just can not set it.
The debugger points to:
0x32d40ae: je 0x32d4110 ; objc_msgSend + 108
0x32d40b0: movl (%eax), %edx
Maybe some issues due to it being treated as an Objective-C class and trying to send a message to set boolean which I know is a bit funny with CoreData originally representing them as NSNumbers.
Any ideas? I created the class myself, it is not generated.
EDIT:
entity.crDate = NSDate() // succeeds
entity.completed = false // fails
entity.completed.setValue(false, forKey: "completed") //succeeds
So for setting the bool, using the setValue of NSManagedObject works but not the direct setters, though for the non-bool properties, I can set it using the setters.
UPDATE:
While checking this a bit more, it seems like the first time I set the value after getting from NSEntityDescription, it uses normal Swift accessor methods. Later on when I try to access the same object (which was stored in an array) it attempts to treat it as a Objective-C style object and sends a message for method named "setCompleted". I guess it makes sense since I use the dot notation to access it and I used the #objc directive.
I tested this by creating a "setCompleted" method, however in the method I set the value using "completed = newValue" which makes a recursive call back to "setCompleted" causing it to crash... Strange, so at this moment still can't don't have a proper fix. It seems to only happen with Bools.
Only workaround is use the "setValueForKey" method of NSManagedObject. Perhaps file this as a bug report?
If you let Xcode 6 Beta 3 create the Swift files for your entities, it will create NSNumber properties for CoreDatas Boolean type.
You can however just use Bool as a Swift type instead of NSNumber, that worked for me without using the dot syntax though.
It will set the Swift Bool with a NSNumber, that maybe leads to a bug in the dot syntax.
To make it explicit you should use the type NSNumber for attributes in the entity with the Boolean type. Then create a computed property (in iBook The Swift programming language under Language Guide -> Properties -> Computed Properties) to return you a Swift Bool. So would never really store a Bool.
Like so:
#NSManaged var snack: NSNumber
var isSnack: Bool {
get {
return Bool(snack)
}
set {
snack = NSNumber(bool: newValue)
}
}
Of course it would be cool to hide the other (NSNumber attribute), but be patient and Apple will implement private attributes in the future.
Edit:
If you check the box create skalar types it will even use the type Bool in the automatically created Swift file!
So I think it is a bug.
Following on from CH Buckingham who is entirely correct. You are attempting to store a primitive type in core data where it is expecting an NSNumber.
The correct usage would be entity.completed = NSNumber.numberWithBool(false)
This is also why you cannot retrieve this completed value as a bool directly and thus you would need to write:
var: Bool? = entity.completed.boolValue()
You can downcast your property from NSNumber to Bool type like this:
var someBoolVariable = numberValue as Bool
It works for me in this way:
self.twoFactorAuthEnabledSwitch.enabled = userProfile?.twoFactorEnabled as Bool
In XCode 8 Just set :
user.isLoggedIn = true
its works like a charm
I haven't touched swift, but in Objective-C, a BOOL is not an object, and cannot be an object. It's a primitive, and it looks like you are attempting to tell an Objective-C class to treat a BOOL like an object. But I could be making that up, as I'm not familiar with what #NSManaged does under the hood.
https://developer.apple.com/library/ios/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/FoundationTypesandCollections/FoundationTypesandCollections.html
I found that it works fine if you specify the class name and module in the data model (instead of leaving the default NSManagedObject).
Once I set that, I can use Bool, Int16, Int32, etc., without any problems.