I am getting a warning:
RS232Msg cannot respond to
"-initWithRS232MsgRawEncoded"
Code is
-(void)createMessage
{
RS232Msg* pMsg;
//pMsg = new RS232MsgRawEncoded(static_cast<int>nMessageNumber); in cpp
pMsg = [pMsg initWithRS232MsgRawEncoded:(int)nMessageNumber];
}
initWithRS232MsgRawEncoded is a derived class of RS232Msg.
and pMsg is a pointer to RS232Msg. The createMessage is a method that is declared in RS232Msg How to make it to access ?
If you defined initWithRS232MsgRawEncoded in a class derived from RS232Msg you cannot use that selector with RS232Msg*.
If I understand correctly what you are trying to do, you would like to add one more possibility of creating RS232Msg objects by initializing them with raw encoding.
You can do that in different ways. One is creating a sort of "factory" class (it would not be an orthodox factory as per GoF patterns, but that does not matter). This class can have a static function that is exactly your initWithRS232MsgRawEncoded.
Another option you have is define a category for RS232 and then add the initWithRS232MsgRawEncoded into it. Categories are a way to extend classes without the need of subclassing them. This is a skeleton of how you would go about it in your case:
#interface RS232 (MyRS232Extension)
(id)initWithRS232MsgRawEncoded:....;
#end
#implementationRS232 (MyRS232Extension)
....
#end
Related
The problem is I don't see the benefit of using associated objects vs static objects defined in the category implementation file with getter/setter methods.
I was thinking about defining the getters and setters in the header file of the category. Like this:
#interface NSObject (test_static)
- (id)getStaticObject;
- (void)setStaticObject:(id)a_static;
#end
and then to declare a static variable in the implementation file and implement getter/setter methods, like this:
static id test;
#implementation NSObject (test_static)
- (id)getStaticObject
{
return test;
}
- (void)setStaticObject:(id)a_static
{
test = a_static;
}
Why I shouldn't use this approach and use associated objects instead ?
Well, I guess I didn't get how properties work and how they've solved the fragile base class problem. Maybe it's related...
There is a huge difference. Associated objects is a way to simulate properties in a category.
Using a single static variable means you have a single, shared value used across all instances.
The choice is which to use depends on your goal. If you want an instance specific result from your two category methods, do not use a static variable - use associated objects. If you want the same object back from the two category methods regardless of the object instance, then use the static variable (and probably change your category methods to class methods instead of instance methods).
I have a base class called Mail that will essentially act as an abstract class which will have concrete subclasses that determine things like the mail's subject, body, sender etc.
Let's call one such concrete subclass NewsMail.
I've set up polymorphic relationships in Obj C before but never in CoreData.
It seems as though the following line is expecting a class thats declared in the xcdatamodel. The following line:
[NewsMail MR_createInContext:[NSManagedObjectContext MR_context]];
produces this error:
"NSInternalInconsistencyException", "+entityForName: could not locate an entity named 'NewsMail' in this model.
Now I could get around this by adding an entity in my xcdatamodel for every concrete subclass I have but this will grow unwieldy after a time.
Advice?
UPDATE
So I have a category 'Mail+Types' where I intend to configure the concrete types:
#import "Mail.h"
#import "MailProtocol.h"
#interface Mail (Types)
+ (instancetype)newInstanceInContext:(NSManagedObjectContext*)context;
#end
#interface WelcomeMail : Mail<MailProtocol> #end
MailProtocol will define the additional methods that a concrete Mail should conform to:
#import <Foundation/Foundation.h>
#protocol MailProtocol <NSObject>
- (NSString*)subjectKey;
- (NSString*)bodyKey;
- (void)build;
#end
The (instancetype)newInstanceInContext:(NSManagedObjectContext*)context; method should return a concrete class but built from the parent Mail class, as pointed out in an answer below:
+ (instancetype)newInstanceInContext:(NSManagedObjectContext*)context
{
return [NSEntityDescription insertNewObjectForEntityForName:#"Mail" inManagedObjectContext:context];
}
I can confirm that the correct concrete class implementation of newInstanceInContext is executed.
Unfortunately, if I try to run build on a WelcomeMail I get an 'unrecognized selector' error because it tries to run it on the Parent 'Mail' class.
You can do it but I suspect not the way you want to. I don't use MR but it seems obvious it has a factory method to create your managed object based on the class name - and because you don't have an Entity with that name it fails.
What I have done is created both Entities in the MOM editor and marked, for example Mail, as abstract then added each subclass as entities which are derived from Mail. Not sure what you want to do with each derived class where this is that much of a burden. After all, each derived class only then needs the additional attributes that class needs which they don't inherit from Mail. Including for example transient attributes which can be used to add business logic by adding behavior that's not part of the stored model.
The other thing I often do which does work is inherit from the managed object in code - model not stored in the MOM - to add additional logic. But in that case I usually add a factory method myself to instantiate the actual MOM Entity. I suspect in this case MR may be trying to help you by creating a MO with the wrong Entity.
Just to elaborate a bit. I usually create a 'base' model object that's not stored in Core Data that looks like:
#interface BaseModel : NSManagedObject
+ (instancetype)newInstanceInContext:(NSManagedObjectContext*)context;
#end
#implementation BaseModel
+ (instancetype)newInstanceInContext:(NSManagedObjectContext*)context
{
return [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([self class]) inManagedObjectContext:context];
}
#end
My actual model object, say Mail (which is defined in the MOM), inherits BaseModel.
I then further derive another class from Mail. Say ExpressMail. ExpressMail inherits Mail. But overrides newInstanceInContext with:
+ (instancetype)newInstanceInContext:(NSManagedObjectContext*)context
{
return [NSEntityDescription insertNewObjectForEntityForName:#"Mail" inManagedObjectContext:context];
}
Basically it creates a Mail MO. I can then add additional logic to ExpressMail. With the obvious understanding that I can't add any properties here that will be persisted outside of what's in Mail.
Not sure if this is what you want but its a pattern I use frequently to do something like what you are trying to do.
UPDATE
Updating after several comment threads. I think we both realized down casting is not going to work. If you really only want to add behavior - i.e. add methods that can decorate or work on your base class - Mail - then categories should definitely work. If you really only need your POMO (plain old mail object) then you can use categories to decorate it / configure it in different ways -- but If you really need to work with a different subclass then you will have to set those up in your MOMD for core data to be able to instantiate them properly for you.
One last, last suggestion. Not sure if you are familiar with a tool called MoGenerator? It generates a matching set of classes -- one private that represents your actual MOM class and another public that you can extend with additional logic. Anyway, it looks like it has a pretty clever way to wrap your entity with the inner private version -- which creates as _Mail -- and then exposes a public version Mail - that you can then modify. All the plumbing is in the _Mail class. (It also takes care of the drudgery of doing the wrapping). I think you might be able to use it to do what you want. Ie generate your models -- and then just create another ExpressMail subclass that inherits from _Mail. Again, I can't be certain and not sure it eliminates the downcasting issue - but maybe worth a try?
Anyway, check it out:
https://github.com/rentzsch/mogenerator
PostScript
I just tried this myself using Mogenerator. And you still can't add anything to a different subclass of your _baseclass that doesn't exist on the base. That is, I can't subclass the _Mail class it would generate (which maps to a Mail entity in the MOMD) -- to create eg ExpressMail -- and add any behavior that's not on Mail. Same problem as before. So see prior conclusions. Doesn't seem possible for some of the reasons already given.
In Objective-C, is there any way to run a specific selector automatically every time an object is instantiated? (I know about +initialize but I need an instance method).
Specifically, I am writing a custom string class (that inherits from my own root class with a similar interface to NSObject) and I am trying to make it 'play nicely' with Objective-C constant strings. To do this, I have the following class definition (as required by the runtime):
// 1) Required Layout
#interface MYConstantString : MYObject {
//Class isa; inherited from MYObject
char *c_string;
unsigned int length;
}
Now, I want to implement my string class by using a pointer to a C-struct inside the class (this "C object" is already well implemented so I basically just want to wrap it in an Objective-C class). Ideally therefore, my Objective-C class would look like this:
// 2) Desired Laout
#interface MYConstantString : MYObject {
// Class isa;
StringObject *string;
}
And then the class and instance methods would just wrap C function calls using that StringObject.
So because I can't have the desired ivar layout (2), I wish to hack around the required ivar layout (1) to work for me. For example:
- (void)fixup {
// Pseudocode
temp = copystring(c_string);
c_string = (void *)StringObjectNewWithString(temp); // Fudge pointer
length = ... // I can do something else with this.
}
So, to return to the question, is there a way to call -fixup automatically, rather than having to do the following every time I make write an Objective-C constant string?
MYConstantString *str = #"Constant string";
[str fixup];
I know this is an obscene hack, and Objective-C constant string interoperability isn't totally crucial for what I need, but it would be nice to be able to use the #"" syntax and make the code more 'naturally' Objective-C.
I'm guessing you left out an important fact: you're using -fconstant-string-class=MYConstantString when building to have the compiler use your class for constant string objects (#"...").
Given that, then, no. There are two significant problems. First, "instance creation" for constant strings happens at compile time, not run time. The reason that there's a required layout is that the compiler does nothing but lay out the string's data in a data section with a reference to the appropriate class object where the isa pointer goes. It doesn't invoke any custom code. It is not necessarily even aware of such custom code at compile time. A given translation unit may not include the constant string class. The reference to that is resolved at link time.
Second, the constant string instance is almost certainly laid out in a read-only data section. There's a good chance that even calling your -fixup method manually as in your question would encounter an access violation because you'd be modifying read-only memory.
You should consider using a class cluster. Make MYConstantString one concrete subclass of an abstract base class. Make it conform to the required layout and just use the character pointer and length ivars as they are. If it would be convenient to translate to StringObject at various points, do that at those points. Implement other, separate concrete subclasses to use StringObject internally, if desired.
MYConstantString *str = #"Constant string";
That can't work because #"..." is an NSString, and it's not only a problem of layout but of instance sizes. If you want 0-copy or anything like that, what you have to do is have something like:
MYConstantString *str = [MyConstantString stringWithNSString:#"Constant string"];
and let -stringWithNSString: recognize when the passed string is a constant one (I'm pretty sure the concrete class of constant strings is easy to recognize, and probably hasn't changed ever for backward compatibility reasons) and then hack it around to grab the pointer to the bytes and similar things.
This question already has answers here:
Create a subclass of a class using parent's init - from another class
(2 answers)
Closed 8 years ago.
EDIT: Yes, I did it wrong. It's well possibly knowing the init method by using a protocol on class level. This is something I rarely do, so that didn't come to my mind at first (see linked question about my answer to it using a protocol). So yes, this question is broken. As bbum said, there should be absolutely no reason to do this.
Background to my question in [1].
For a design reason (data mapper pattern) I need to initialize classes which I know are subclasses of a certain base class (ManagedEntity). I assert for this once - then later I want to create as many instances, and as fast as possible (I'm programming for iOS). However, since the class where I need to create the concrete instances in doesn't know any of the model classes, the meta class stored and used to create entity instances of is just known to be of type Class.
Long story short: I can't simply use [[[_EntityClass] alloc] initWithBlah:something], since EntityClass is unknown, just known as type Class there, hence the init method initWithBlah is unknown of course - but I know it must exist (it must be by design a subclass of the base class, which is asserted once when the mapper is initialized).
So in order to create instances of the unknown class with the init method that I know it exists, I need to construct a method invocation. This should call the initWith:something selector on the unknown class and create an instance of it.
I think I should use objc_msgSend rather than NSInvocation, because the latter is supposed to be an order of magnitude slower [2]. The init method is supposed to not change, and requires one argument.
So... What would be the equivalent to:
ManagedEntity *newEntity = [[ManagedEntity] alloc] initWithEntityDescription:_entityDescription];
with objc_msgSend?
[1] Create a subclass of a class using parent's init - from another class
[2] http://www.mikeash.com/pyblog/performance-comparisons-of-common-operations-leopard-edition.html
Better:
Class klass = NSClassFromString(className);
id newEntity = [[klass alloc] initWithEntity:entity insertIntoManagedObjectContext:ctx];
There is no reason to use objc_msgSend() directly when you have a fixed selector. You can always call the selector directly using the normal syntax. Worst case, you might have to type-cast the return value of one of the calls.
The only requirement is that the compiler has seen the declaration of initWithEntity:insertIntoManagedObjectContext: sometime prior to compiling the above call site.
Example:
#interface NSObject(BobsYourUncle)
- (void)bob:sender;
#end
...
Class klass = NSClassFromString(#"NSManagedObject");
[[klass alloc] bob:nil];
The above compiles just fine. Not that I'd recommend hanging random definitions off of NSObject. Instead, #import the abstract superclass's declaration (which should contain the selector declaration).
id cls = NSClassFromString(className);
id alloced_cls = objc_msgSend(cls, #selector(alloc));
id newEntity = objc_msgSend(alloced_cls, #selector(initWithEntity:insertIntoManagedObjectContext:), entity, ctx);
return newEntity;
Let us say that application has a concept of cars in it. A car is an instance of Car. There are a small number of possible cars and most, but not all of the data about a car is known at design time. Each kind of car is a singleton; there is at most one of each kind of Car per app.*
Since they are singletons, and since they are named, that suggests some sugar. The most important piece of sugar is this: when I import "Car.h", into a file, I want the symbols "MAFerrari", "MAMercedes", and "MAMclauren" to start showing up in my autocomplete where ever code completion thinks I am trying to provide an instance of a Car*.
My next greedy desire is that I want to be able to send instance methods to my MAFerrari literal, e.g. [MAFerrari topSpeed] means "get the singleton instance of Car that corresponds to the Ferrari and send topSpeed to it", but I acknowledge the utter triviality of this. Even pragmatists should know what their Utopia looks like.
Finally, if possible, I want clean way to declare the constant properties of the three cars as literal data at the top of my Car.m file.
Now, again, I don't actually expect all of that to be possible in Objective C. I just want to know how close we can get to that all that.
The closest idea I've had is to subclass Car for each type of car and provide a +sharedInstance method for each one. sharedInstance can implement the singleton pattern: if it's initialized, return it, otherwise initialize it, store it (where? it should be private to the Car class hierarchy), then return it. Each subclass can implement its own initializer which contains the defaults for that subclass.
Here's what I don't like about this:
I think I have to import all the header files whenever I work with these subclasses. This absolutely sucks. Is there another way?
I have to create .m/.h file pair for every one of these subclasses. That seems like a lot of boilerplate, since they have no unique behavior.
[[MAFerrari sharedInstance] topSpeed] isn't quite as good as [MAFerrari topSpeed], but I acknowledge that this is trivial.
Anyway, how would you do it?
*In reality, it's not cars, but in-app purchase assets, for the curious.
It sounds like what you want is just a global variable. You can create a global variable named whatever you want (say, MAFerrari) and stick whatever you want in it — whether the contents of the variables are instances of multiple singleton classes or multiple instances of the same class doesn't really matter from the point of view of having global names to refer to the objects.
Easy-peasy.
Note that these aren't singletons; they're just long-lived instances of a class stored in global variables.
// Bolt.h
#import <Foundation/Foundation.h>
#interface Bolt : NSObject
// Properties
- (instancetype)initWithLength:(NSUInteger)length
diameter:(NSUInteger)diam
thread:(NSUInteger)thread
grade:(NSUInteger)grade;
// etc.
#end
extern Bolt * twentyFiveByTwelveCoarseThreadGradeEightBolt;
extern Bolt * fiftyByTenFineThreadGradeFiveBolt;
//
// Bolt.m
#import "Bolt.h"
Bolt * twentyFiveByTwelveCoarseThreadClassEightBolt;
Bolt * fiftyByTenFineThreadGradeFiveBolt;
// This will be run before main() but after classes are loaded
__attribute__((constructor))
static void initialize_global_Bolts(void)
{
twentyFiveByTwelveCoarseThreadClassEightBolt = [[Bolt alloc] initWithLength:25
diameter:12
thread:175
grade:8];
fiftyByTenFineThreadGradeFiveBolt = [[Bolt alloc] initWithLength:50
diameter:10
thread:1
grade:5];
}
#implementation Bolt
- (instancetype)initWithLength:(NSUInteger)length
diameter:(NSUInteger)diam
thread:(NSUInteger)thread
grade:(NSUInteger)grade
{
// Do initialization
}
#end
Now you can do things like [fiftyByTenFineThreadGradeFiveBolt maximumTorque]; wherever Bolt.h is imported.
You can't put dictionary or other literals at top level, because they resolve into method calls, which can't be used outside of other methods.