Let me make sure first I have X-Code 4.3.2 version and iOS 5.1 SDK. I have below methods used in my project for core-data operation. Both method giving same warning. i.e "Incompatible pointer types returning 'NSManagedObject *' from a function with result type 'NSManagedObject <Protocol> ".
Method A:
- (NSManagedObject<Protocol> *)newMOforNilMOC
{
return [[NSManagedObject alloc] initWithEntity:[self entityDescription] insertIntoManagedObjectContext:nil];
}
For method method A I just do typecasting and added (NSManagedObject<Protocol>*) then warning get removed as stated below.
- (NSManagedObject<Protocol> *)newMOforNilMOC
{
return (NSManagedObject<Protocol> *) [[NSManagedObject alloc] initWithEntity:[self entityDescription] insertIntoManagedObjectContext:nil];
}
Method B:
+ (NSManagedObject<Protocol> *) newInContext:(NSManagedObjectContext *)context
{
return [[NSEntityDescription insertNewObjectForEntityForName:[[(NSManagedObject<Protocol> *)self class] entityName] inManagedObjectContext:context]retain];
}
For method B when I do typecasting it will not work hence I just change the name of method from newInContext to AddnewInContext (Found somewhere when googled) then warning got removed.
I have following Questions:
If first method is required typecasting then why second one is not working with that solution?
What is the exact meaning of changing the name of method. Is this proper way to remove above warning? Why typecasting not working in
method B?
This could be complicated one but feel free to leave comment if you have any doubt. Because I want to know the difference, at least I get to learn some new thing about core data.
I think you are using 'self' in a class method. You should use the class itself. Let me show by code
+ (NSManagedObject<Protocol> *) newInContext:(NSManagedObjectContext *)context
{
//Usage of [self class] is not correct, as self points already to a class.
NSEntityDescription* desc = [NSEntityDescription entityForName:#"myObjectName" inManagedObjectContext:context];
return [[NSEntityDescription insertNewObjectForEntityForName:desc inManagedObjectContext:context]retain];
}
You can't cast a class type to a 'id' type, which is the one that self points to if you are inside an object method, not a class method. I don't think any method renaming solves any warning.
Related
How do I call a non-void function? Normal [self methodName]; works. But how do I do this for a method that returns an NSString. I keep getting an error. For example:
+ (NSString *)formulateYQLRequestFor:(NSArray *)tickers
How do I call this? [self formulateYQLRequestFor]; gives me an error.
Sorry about the formatting, for some reason safari won't let me indent.
Thanks!
+ designates a class function. You call it with the class name, not an instance.
Instead of:
[self formulateYQLRequestFor:myArray];
Do this:
[MyClassName formulateYQLRequestFor:myArray];
Alternatively, you can do this:
[[self class] formulateYQLRequestFor:myArray];
You don't have to do anything with the return value if you don't want to. At least with ARC, the return value will be automatically released. However, since it's unlikely that the function does anything on its own, you probably should do something with the return value:
NSString *returnValue = [[self class] formulateYQLRequestFor:myArray];
// Do something with returnValue
Finally, if you want to call the function without passing in an array, you still need the array parameter, but perhaps the function will accept nil for the array:
NSString *returnValue = [[self class] formulateYQLRequestFor:nil];
There are two problems with your call to [self formulateYQLRequestFor];
Firstly, the method takes a parameter, which you haven't provided. Because of this, the compiler is looking for the method called formulateYQLRequestFor instead of formulateYQLRequestFor: This is significant, because the : is part of the method name in Objective-C. So you are trying to call a method that doesn't exist.
Secondly, self is sending a message to an instance of your class. The + in the method signature indicates that you have a class method, and so self does not respond to the method you are trying to call.
The correct way to do this is:
NSString *resultString = [[self class] formulateYQLRequestFor:someArray];
where someArray is a valid NSArray parameter.
I don't know what - (NSString *)formulateYQLRequestFor: does with the NSArray, but if it isn't necessary you can just call [self formulateYQLRequestFor:nil];. Alternatively you can call it with an empty array [self formulateYQLRequestFor:[NSArray array]];.
I am designing a new application by modernizing code I wrote in the past. This old code uses the class/delegate model and I am trying to transform them to use blocks as callbacks, not the delegate stuff.
What I do is to create a property like
#property (nonatomic, copy) void (^onTouch)(NSInteger index);
That would pass to the object using that class a block where code can be inserted and in this case executed on touch.
But my problem is this. When you use delegates and you have a method on the delegate protocol, Xcode will warn if you use that class and forget to implement the delegate protocols. Is that a way to do that with blocks? Or in other words: is there a way to make Xcode complain if a callback block is not defined by the caller?
I mean this would be the correct:
MyClass *obj = [[MyClass alloc] init];
obj.onTouch = ^(NSInteger *index){ //call back code to be executed };
This would be OK too
MyClass *obj = [[MyClass alloc] init];
obj.onTouch = nil;
but this would generate a message
MyClass *obj = [[MyClass alloc] init];
// no callback block defined.
Is this possible?
If you want to enforce setting a certain parameter, I would include it in the initializer.
MyClass *obj = [[MyClass alloc] initWithBlock:^(NSInteger *index) { /* code*/ }];
Then, in MyClass:
- (id)init {
// This will result in a runtime error if you use the wrong initializer.
NSAssert(NO, #"Use initWithBlock instead.");
}
- (id)initWithBlock(initWithBlock:^(NSInteger *)block) {
self = [super init];
if (self) {
self.onTouch = block;
}
return self;
}
Also note, attempting to execute a NULL block results in a crash, so make sure to do:
if (self.onTouch) { self.onTouch(); }
Wherever you run the block.
First, I strongly recommend defining types to represent your blocks - makes them a lot easier to work with, especially if you need to refactor the parameters.
You can't write code that distinguishes between "I set this property to nil" or "the runtime initialized this property to nil", at least not without some crazy runtime code to check the stack. Only option I can think of would be to use the null object pattern. Before I elaborate, bear in mind that I haven't actually tried to test this, but it should work. Define a block that means 'has no value' and set your property to point to that block on init. Then you can compare to that NullBlock at runtime to identify if someone explicitly set the property to nil (because it would be nil at that point) or gave it a real non-nil value.
Alternatively, if you don't mind manually writing your set accessors, you could have a BOOL that tracks if someone set the property explicitly. Then when you call the block just check if someone actually set the value or not.
#synthesize onTouchBlock=_onTouchBlock;
MyBlock _onTouchBlock;
BOOL _onTouchBlockWasSet;
- (void)setOnTouchBlock:(MyBlock)block {
_onTouchBlockWasSet = YES;
_onTouchBlock = block;
}
I would not recommend passing the value in the initializer because that makes it tied to the creation of that object type. If you wanted to change the block in code based on some condition, you'd be back to square one. Also, it prevents you from using storyboards which create that object.
Unless I misunderstood it, this LINK from Apple's documentation clearly states that the class initializer, "+ (void)initialize)", only executes once per class.
Here is the excerpt:
Special Considerations
initialize it is invoked only once per class. If you want to perform independent initialization for the class and for categories of the class, you should implement load methods.
However, I'm getting a weird behavior on my project and the initializer is being executed twice. So I have to check if _classContext is null. I only got one class that has this method. What are the possible reasons why this is happening?
I'm using XCode 4.5.2 and OS X 10.8.2. I got multiple iOS simulators, iPhone 5.1 and 6.0.
+ (void) initialize
{
num++;
NSLog([NSString stringWithFormat:#"Times: %i", num]);
if(_classContext == nil)
_classContext = [[myClass alloc] init];
}
This will happen if you have a subclass of this class. The initialize method will be called for the class and each subclass.
The proper way to code the initialize method is:
+ (void)initialize {
// Replace ThisClass with the actual class name
if (self == [ThisClass class]) {
// do initialization here
}
}
+initialize can be called more than once and one should use caution when overriding +initialize.
Please read the blog post +initialize Can Be Executed Multiple Times (+load not so much) at bbum's weblog-o-mat.
I have a sample app which i downloaded from net
In this i was unable to understand following code
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif == nil)
return;
also
if (!array1)
return;
does this code means if object does not exists then return.....
HELP
In Cocoa, an initialiser will either return an object pointer if the call was successful, or a nil if it was unable to create the object.
Both cases are checking for the existence of the object. Actually, checking for the existence of a pointer to the object and simply returning if the object does not exist. As an example, here is a common form of initialiser for an object.
- (id)init {
// Call the superclass initialiser first and check that it was successful.
if (!(self = [super init])) {
// If the superclass initialiser failed then self will be nil.
// return a nil because we cannot create this object.
return nil; // Bail!
}
// Do more initialising
// If we can initialise the superclass and ourself, return a pointer to ourself
return self;
}
However, the snippets you have provided are not enough to tell whether the code is correct. For example, the first example is incorrect if it is part of an initialiser method because it is not returning any kind of object.
Edit
From your further examples both of these print hiiiiiiii
NSArray *arr;
if(arr) { NSLog(#"hiiiiii");
and
NSArray *arr = [[NSArray alloc]init];
if(arr) { NSLog(#"hiiiiii");
In the first case you are declaring arr to be a pointer to an NSArray, but because it hasn't been initialised this pointer is just a garbage value of random numbers. But it isn't nil So your if-statement evaluates as true. That doesn't mean that it is a valid pointer to an NSArray.
In your second example you declare an NSArray pointer and initialise it. This was successfully initialised so the pointer is not nil and the if-statement evaluates as true. In this case you do have a valid NSArray pointer.
Declaration is not initialisation!
Maybe if you explain what it is that you are trying to do we'll be able to better answer your questions.
They are both checking if the object is nil. In the first case it seems a bit silly though :)
Yes, except in the first case localNotif will not be nil because it has been set
I'm trying to declare a variable inside an if statement. If the result of a query is YES then the object will be of one type, otherwise it will be of another type. A bit like this...
if (YES) {
ObjectTypeA *object = [[ObjectTypeA] alloc] init];
}
else {
ObjectTypeB *object = [[ObjectTypeB] alloc] init];
}
Once that's done I want to use object with the same methods no matter what type it is. I tried declaring object as an id before the if statement but get an error: member reference type 'struct objc_object *' is a pointer; maybe you meant to use '->'?
I also tried declaring both to be separate objects outside the if and then make the pointer point to whichever it was once I knew. That wouldn't work either.
I know that the compiler is trying to protect me from myself by doing this but in this circumstance I need a way round it please.
Thanks.
The most common pattern for this problem in Cocoa/Cocoa Touch is to define a protocol.
A protocol is a collection of methods that can be implemented by any object.
If you make ClassA and ClassB conform to a protocol containing the methods you need them to respond to then you don't need to worry about which type of object you get.
The idea is "if it looks like a duck and quacks like a duck, then it's probably a duck".
You can use dynamic typing and create your objects depending on the outcome of your query, but ensure that the resulting object conforms to a particular protocol, like so:
id <MyProtocol> myObject;
if (YES)
myObject = [[ClassA alloc] init];
else
myObject = [[ClassB alloc] init];
[myObject myMethod];
[myObject release];
I think this code should work well:
id obj = nil;
if (YES) {
obj = [[ObjectTypeA] alloc] init];
} else {
obj = [[ObjectTypeB] alloc] init];
}
[obj performSelector:#selector(YOUR_METHOD) withObject:YOUR_OBJECT];
You want dynamic typing :)
The way around this is to declare a third object that both of these inherit from
OR
You could use the adapter pattern and create an object that accepts both of these objects as a member and then wrap the functions you wish to call into that object
good luck!
--> These are genral OO solutions; I'm not a Objective-C developer