How to upgrade NSCoding's initWithCoder as properties in a class are changing? - nscoding

My class has some added properties and I change my class's initWithCoder to parse out the new types.
This causes a crash if the archive file is still using the old format. How do I sensibly implement the code without causing such a crash as properties changes in a class over time?

Related

"Cannot define category for undefined class" error in Xcode 11.3, no access to source file

I'm trying to make a category for a class that gets defined in a source file I don't have access to, namely RunnerViewController.
The two important files here are iPad_RunnerAppDelegate.h and FilesBrowser.mm. I do not have access to the header file's corresponding source file.
iPad_RunnerAppDelegate.h contains a forward declaration to the RunnerViewController class, and can reference that class with no difficulties.
However, if I try to #include "iPad_RunnerAppDelegate.h" in FilesBrowser.mm and then try to create a category in the same file, it doesn't recognise the class name.
Despite this error appearing, I can still use the RunnerViewController class inside FilesBrowser.mm, I just can't make categories for it.
What's happening here, and how would I fix it?
I've had to do this same thing but it was a long time ago. The problem is that without some indication of where to apply the category, your code cannot work alone. What you need is info to the compiler to let it know where it's going to insert the category.
In FilesBrowser.mm, you will tell it by adding this BEFORE "iPad_RunnerAppDelegate.h":
#interface RunnerViewController: UIViewController // or whatever it actually subclasses
#end
Now the compiler knows that its going to insert the category against an Objective C class named RunnerViewController.
But - you're not completely done. Now you need to insure that the runtime / loader do the class loading and category insertions at the proper time. This is where my knowledge gets a bit fuzzy, so it may not turn out to be a problem at all.
What I believe needs to occur is for the RunnerViewController class to get loaded first, then later at some point the category you wrote applied to it (but this may not be necessary). So if RunnerViewController is statically linked into your app (using a .a archive), then you're good for sure. But if that class is in a dylib loaded dynamically, and your category is statically linked - well that might be a problem. I just don't know how long Apple waits to try and deal with the categories (which by the way the -ObjC link flag is for.
In any case try the code above first and just see what happens. If RunnerViewController is dynamically loaded, and you get some hard runtime error, there is a workaround where you would make your category go into a module/framework that is also dynamically linked, but gets linked after RunnerViewController.
In the end I believe you have a good chance of making this happen.

Objective c runtime method creation and subclassing limits

I was trying to create a subclass of the class WFAirportViewController in the new WiFiKitUI private framework for iOS 11 during runtime. The class is used as the interface of the wifi connection scene in the settings app. My intention is to create a subclass so that I can keep all the functionality and change up the looks of the views. That didn't work as I try to execute the code it just crashes. Then I tried to create a new method for the class with class_addMethod, it returned false meaning that the method creation wasn't successful, but when I tried to get the class in runtime with objc_getClass it did work so it means that the class is retrievable. Is there some kind of restriction for runtime subclassing and method creation that is not documented because I have searched for a while now and nothing shows up.

Fetched Result Controller delegate not called after swift 1.2 / xcode 6.3 update

I just upgraded my project to swift 1.2. And after 5 or 6 consecutive 'Convert to latest Swift' action :), i was able to make it compiles.
Then i had lot's of my UI test failing. It was due to the fact that my 'NSFetchedResultsControllerDelegate' was not called any more.
After (i might say) a very lucky attempt, i found that it as due to the fact that my delegate was not a NSObject. So i was able to fix it by subclassing NSObject or adding #obj.
Before:
class BasicFetchedResultControllerDelegate : NSFetchedResultsControllerDelegate
After:
class BasicFetchedResultControllerDelegate : NSObject, NSFetchedResultsControllerDelegate
I don't think i saw something related to this in the change log. What is the changes that lead to that.
Did you notice other changes like this?
I received this from Apple after i filled up a bug report:
This issue behaves as intended based on the following:
This is a behavior change in Swift 1.2: methods in non-Objective-C-derived classes will no longer be implicitly marked #objc even if they match an Objective-C protocol. You can explicitly mark the methods with the #objc attribute if you don't want to extend NSObject. This is described in the Xcode 6.3 release notes at https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc6_release_notes.html#//apple_ref/doc/uid/TP40001051-CH4-SW3.
Core Data classes are still very much behaving like legacy Objective-C classes. As NSFetchedResultsController is a #protocol without any superclass, Swift needs the explicit NSObject declaration.
And you are right, there is nothing about that in the change logs.

Swift - CoreData’s NSManagedObject subclass

When creating NSManagedObject subclasses in Swift, I get an error:
2015-02-12 00:12:57.662 MyApp[1934:272844] CoreData: warning: Unable to load class named ‘ClassName' for entity 'ClassName'. Class not found, using default NSManagedObject instead.
I can fix this by manually adding #objc(ClassName) in the Swift subclass, but not only does this defeat the purpose of automatic subclassing, but I don’t want to waste my development time adding this to all two dozen NSManagedObject subclasses.
Originally I did this and just got over it. But this time I needed to change my model and generate all subclasses again and have a deadline coming up, so what would be the correct way to overcome this error so regenerating my model’s subclasses doesn’t mean wasting so much time/patience.
Thanks as ever
You are out of luck. Some things in Swift just do not (yet) work the way they used to in Objective-C.
Consider writing a script (in Perl, Python - or Swift!) to insert the missing line. For example, the first line of the class declaration is always on the same line, so it should be trivial to extract the class name and insert the corresponding #objC call.

Can I add properties to subclass of subclass of NSManagedObject?

I have a class Base : NSManagedObject generated by core data, and in order to add some methods to this entity, I subclass it with Derived : Base. Now, I want to add a property (which is not in Base class) to Derived class. But when I try to access the setter of the added property, it throws an exception:
caught "NSInvalidArgumentException", "-[Base setAddedProperty:]: unrecognized selector sent to instance 0x7fdcc31b36d0"
Could anyone help?
EDIT: It seems that subclass of subclass of NSManagedObject cannot have its own methods because I just added a method to Derived and got the similar exception. Does that mean category is the only way to add methods to subclass of NSManagedObject?
EDIT: I changed the "Class" of entities in configurations to Derived and everything is working now. All those newly added properties can be accessed and customized methods can be invoked. Why? and is this a good practice?
EDIT: It seems the above descriptions are misunderstood. I intend to subclass the entity classes generated by core data in order to provide customized methods and properties, not to create child entities. Therefore, Derived is not an entity in data model.
You also should specify inheritance in xcdatamodel . Check fields: Name, Class, Parent Entity in xcdatamodel. Derived : Base isn't enough for NSManagedObjectsubclasses.
You need to select parent sheep (also try to set abstract entity for you Base)
I got this problem fixed.
In my .xcdatamodeld file, I mapped Base entity to Base class. In my codes, I create an instance by:
Derived* pointer = [Derived MR_createEntity];
This method invokes NSEntityDescriptor insertNewObjectForEntityForName:inManagedObjectContext for me. However, this method will return an instance of Base instead of Derived despite the pointer is of type Derived*, which should be an syntax error if in compilation.
Therefore, in order to make my methods in Derived valid, I need to manually change the mapping from Base to Derived.
EDIT:
After writing this answer, I found an awesome tool mogenerator, which makes use of exactly the same idea as I described above and is really convenient.

Resources