Xcode12; New “Subclass MPMediaItem must implement -valueForProperty” error - ios

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
}
}

Related

Override URL description

Originally I tried to use something like this:
extension URL: CustomStringConvertible{
public override var description: String {
let url = self
return url.path.removingPercentEncoding ?? ""
}
}
After fixing compiler warning code became:
extension URL{
public var description: String {
let url = self
return url.path.removingPercentEncoding ?? ""
}
}
but
print(fileURL) still shows old URL description with percentages.
You can't override a method in an extension. What you're trying to do isn't possible in Swift. It's possible in ObjC (on NSURL) by swizzling the methods, but this should never be done in production code. Even if you could get the above working in Swift through some trickery, you should never use that in production code for the same reason. It could easily impact you in very surprising ways (for instance, it could break NSCoding implementations that expect description to work a certain way.
If you want this style of string, create a method for it and call that when you want it. Don't modify description in an existing class.

Swift 3 enums leak memory when the class contains an array

I found a memory leak in Swift. It gave me nightmares because my code was full of small leaks everywhere, and then I managed to reduce it to this small example,
import UIKit
enum LeakingEnum {
case
LeakCase,
AnotherLeakCase
}
class Primitive {
var lightingType: LeakingEnum = .LeakCase
var mysub : [Int] = []
init() {
mysub.append(80)
}
}
class ViewController: UIViewController {
var prim: Primitive?
override func viewDidLoad() {
super.viewDidLoad()
prim = Primitive()
}
}
If you run this program on an iPhone and Profile with Instruments, you'll find this leak in Array._copyToNewBuffer,
If I remove the call to mysub.append, it stops leaking. If I remove the enum from Primitive, it stops leaking as well. All the classes where I have an enum leak like this. What's going on with Swift enums?
Reproduced in Swift 3, Xcode 8.2.1, and iOS 10.2, on both an iPhone6 and an iPad Pro. Can't reproduce in the Simulator, or in a device with iOS 9.3.2.
You can download a minimal sample app here: https://github.com/endavid/SwiftLeaks
Is this a known bug? Is there any work around?
Edit:
Because this remind me of another enum bug, Accessor gives the wrong value in Swift 1.2/2.0 Release build only, I tried making the enum an #objc Int enum, but it still leaks. However, making lightingType directly an Int does fix the leak...
Edit2:
After updating my iPhone to 10.3 and Xcode to 8.3, the leak is gone. It seems it was an issue of iOS 10.2...
Hey #endavid managed to replicate the issue consistently. We spend a good time trying to figure out what was going on and your post helped a lot!
Here is the sample repo: https://github.com/Giphy/ios-memory-leak-sample
Radar: https://openradar.appspot.com/radar?id=4992108083544064
We are developing SDKs and same exact issue surfaced with a small difference. Since we wanted things to interop we added #objc to the enum definition and things started to leak exactly the way you described given your class has two properties, one enum and one mutable array.
Consistently reproduced the leak:
// Without #objc this enum won't leak
// however when this enum is included in a class
// which contains an array, it will leak
#objc enum leakingObjCMarkedEnum: Int {
// Just some random cases.
case apple, orange
}
// Wrapper class which contains an enum and Array
// The class needs to contain the the Array in order for
// the Enum to leak.
class WrapperClass {
// Optional enums marked with #objc will leak.
var leakyOptionalEnum: leakingObjCMarkedEnum?
// Include an array to trigger this behaviour.
// Empty arrays won't cause the leak, so lets add an arbitrary Int
var myArray: [Int] = [80]
}
class ViewController: UIViewController {
// Hang on to a reference to our Wrapper Class instance.
var wc: WrapperClass?
override func viewDidLoad() {
super.viewDidLoad()
// Allocate an instance of our class
// and things will start leaking at this point.
wc = WrapperClass()
}
}
Work Around:
If we convert the optional enum class property to a non-optional, leak will disappear.
// Let's convert the optional property to a non-optional
var leakyOptionalEnum: leakingObjCMarkedEnum = .orange
Edit:
It is fixed by guys # Apple:
https://bugs.swift.org/browse/SR-5625
PR: https://github.com/apple/swift/pull/11341

What is the cause of EXC_BAD_ACCESS crashes for classes declared in separate files?

I have come across this problem several times now, without ever finding the cause.
When attempting to access a property of ClassY in ClassX I get an EXC_BAD_ACCESS error. This happens even if I instantiate a clean copy and attempt to access the property immediately:
let classY = ClassY()
println(classY.someTextProperty)
EXC_BAD_ACCESS
As far as I am aware this error should only be caused by trying to access a deallocated instance, which presumably cannot be the case in the above code.
Where it gets strange, is that if I declare ClassY in the same file as ClassX then the problem disappears. (ClassY does have some private properties, but I am not trying to access these and anyway, making them all public does not solve the problem)
I am not including the source code here since there is more of it than is practical to isolate. I have not been able to reproduce this reliably in a standalone project because I am unable to find any kind of pattern.
Has anyone come across a similar kind of problem, and does anyone have an idea for a solution (obviously I can include the definition in the same file, but that is a workaround rather than a solution)?
I am currently running iOS 8.3 / Swift 1.2 but had this problem already in iOS 8.1.
UPDATE
Following lots of trial and error, it seems that the problem comes from lazy properties and protocol conformance. Again this is not something I can reproduce in a plain playground (perhaps the declarations need to be in different files).
My ClassY conforms to ProtocolY which has several properties:
protocol ProtocolY {
var number: Int { get }
var text: String { get }
}
When ClassY conforms to ProtocolY, if it implements either of the properties as a lazy property then accessing a property causes the EXC_BAD_ACCESS crash. If ClassY is not marked as conforming to ProtocolY or if none of the properties declared in ProtocolY as implemented by ClassY are lazy properties then no crash occurs.
Obviously this is just narrowing down but still does not give me an explanation. I know of no reason why implementations of protocol properties should not be lazy.
UPDATE Here is an example of properties on ClassY:
private(set) lazy var currentPage: Int = {
let subject: RACReplaySubject = RACReplaySubject(capacity: 1)
subject.sendNext(self.currentPage)
return subject
}()
var currentPage: Int {
didSet {
(self.currentPageSignal as? RACSubject)?.sendNext(self.currentPage)
}
}
currentPage is set in the init method.
If I use instead:
private(set) var currentPage: Int = {
let subject: RACReplaySubject = RACReplaySubject(capacity: 1)
return subject
}()
var currentPage: Int {
didSet {
(self.currentPageSignal as? RACSubject)?.sendNext(self.currentPage)
}
}
(and do a sendNext in the init method) then everything works fine.
I'm fairly confident that the fact that I'm using ReactiveCocoa is irrelevant - I have also tried lazy properties which are simple Strings, with the same result.

Swift - casting a nil core data string as an optional value

I have a field stored on a core data object called "metadata" which is of type String (no optional, because Apple docs say not to mess with optionals in CD). Sometimes, the metadata field is nil. In checking whether this value is nil, I do the following check:
if object.metadata as String? != nil {
...
}
However, my code continuously crashes on this line as an EXC_BAD_ACCESS. I have also tried:
if let metadata = object.metadata as String? {
...
}
Which doesn't work either. I cast objects successfully to optionals in other parts of my code, so I don't understand why this particular case isn't working. How do you check whether a core data property is a nil string?
It looks like what you really want is this:
if object.metadata != nil {
...
}
or this:
if let metadata = object.metadata as? String {
// You can now freely access metadata as a non-optional
...
}
--EDIT--
My mistake, I didn't read the first part of your question thoroughly enough. It looks like the duplicate answer has a solution for this. Essentially, the generated managed object subclass is a bug and you should modify the properties to be either optional or implicitly unwrapped. You can check both of those using the first method for implicitly unwrapped and second for optionals.
There are several questions which discuss the issue of the generated subclasses not producing optional properties. I wouldn't be too concerned about editing the subclasses; there's nothing special about them except that Apple is making it easier to create them.
Check if property is set in Core Data?
Swift + CoreData: Cannot Automatically Set Optional Attribute On Generated NSManagedObject Subclass
--Edit2--
If you really don't want to touch the subclass you can access the property using valueForKey() and could add that as an extension if you wanted something a bit cleaner.
if let metadata = object.valueForKey("metadata") as String? {
...
}
In an extension:
extension ObjectClass {
var realMetadata: String? {
set {
self.setValue(newValue, forKey: "metadata")
}
get {
return self.valueForKey("metadata") as String?
}
}
}

updateValue not working for Dictionary

I'm creating a test app using Swift in Xcode, and I've run into an annoying issue. I'm writing a simple class that will act as a cache using a Dictionary object. My implementation is below:
import Foundation
import UIKit
class ImageCache {
var dict:Dictionary<String,NSData>?;
init() {
dict = Dictionary<String,NSData>();
}
func exists(id:String) -> Bool {
return dict!.indexForKey(id)!==nil;
}
func getImage(id:String) -> UIImage? {
if(!exists(id)) {
return nil;
}
return UIImage(data: (dict!)[id]);
}
func setData(id:String, data:NSData) {
dict!.updateValue(data, forKey: id);
}
}
The issue is in the last method, with Xcode stating "Could not find member 'UpdateValue'". This is weird, because the code hint seems to show it just fine:
But when I try to compile:
Could this potentially be a bug in Xcode? Or am I missing something super-obvious?
this is not a bug or a quirk in the compiler.
it is how Optional implemented (which may be flawed or not)
what happened is that the Optional store the Dictionary as immutable object (with let perhaps). So even Optional it is mutable, you can't modify the underlying Dictionaryobject directly (without reassign the Optional object).
updateValue(forKey:) is mutating method, you can't call it on immutable object and hence the error.
you can workaround it by doing
var d = dict!
d.updateValue(data, forKey: id)
because you copy the dictionary to another mutable variable, which then is mutable and able to call mutating method on it
but without dict = d, your change won't be applied on dict because Dictionary is value type, it makes copy on every assignment
related answer
Smells like a bug or a quirk in the compiler.
I just tried something like
var d = dict!
d.updateValue(data, forKey: id)
and it works as expected.

Resources