Can anyone please suggest alternative to this line of code so that my code becomes compatible with ARC.
[animation setTimingFunction:(CAMediaTimingFunction*)UIViewAnimationCurveEaseInOut];
That code isn't correct even in MRR (non-ARC). The only reason it's not crashing is because UIViewAnimationCurveEaseInOut happens to have the value of 0 (which becomes nil after the cast).
Instead you should be using
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
This will do what you're intending to do, except with an actual instance of CAMediaTimingFunction*.
Related
In a class I have a variable myColor of type CGColorRef declared as follow:
#implementation MyClass
{
.......
CGColorRef myColor;
.......
Here are two lines of Objective C code:
First line:
myColor=[UIColor orangeColor].CGColor;
Second line:
myColor=[UIColor colorWithRed:1.000 green:0.500 blue:0.000 alpha:1.000].CGColor;
I first expected them to be equivalent, but they are not.
I know they are not equivalent, because when I use the first one my program works. And when I use the second one it crashes later down the road. Showing more code here would be totally irrelevant to the question.
Can someone explain the difference? That will hopefully allow me to modify my code and be able to use the second line.
Just for reference, it crashes in (with: Thread 1: EXC_BAD_ACCESS (code=1, address=0x881b370e0)):
- (void)drawRect:(CGRect)rect
{
.......
CGContextSetStrokeColorWithColor(context,myColor); // Crash here !!!
CGContextStrokeEllipseInRect(context, rectangle);
.......
}
You're assigning to an instance variable of Core Foundation type CGColorRef. That type is not an ObjC object type, so is not subject to ARC (automatic memory management), which means you need to manage its memory manually.
Both of your examples are actually incorrect, but the reason you don't see the crash initially when you assign [UIColor orangeColor].CGColor is because of a lucky coincidence: the orange color object is probably a long-lived singleton object, and its internal CGColor reference is thus also long-lived, so your assignment to ivar works and later access happens to work-- but this is just a red (orange?) herring.
You do see a crash in the other case because the UIColor object that you create in passing ends up being immediately deallocated because it's not used again. Thus the CGColorRef value that you pull from it and assign to your ivar is is also immediately invalid and radioactive when you try to use it later.
To store a CGColorRef safely in your object, you need to have ownership of it, which in your case means explicitly retaining the CGColorRef you get from UIColor:
myColor = CGColorRetain([UIColor colorWithRed:1.000 green:0.500 blue:0.000 alpha:1.000].CGColor);
Or even better would be to bypass UIColor altogether, and just use the function that directly gives you a color ref with create ownership semantics:
myColor = CGColorCreateGenericRGB(1.0, 0.5, 0.0, 1.0);
In either case, you now "own" this reference, which means it's safe to use later, and also means you're responsible for cleaning it up when you're done, e.g.:
- (void)dealloc
{
CGColorRelease(myColor);
}
See also this Apple Tech Q&A doc that goes into almost this same example.
The form of memory management required with Core Foundation objects (CGColorRef is one of them) is very similar to the older, pre-ARC ObjC manual system, where you increment a retain count at the point where you wish to hold ("own") the reference, and then decrement (release) when you no longer need it to be valid. Apple has good docs for how to best think about this. In this case, assigning the reference to your instance variable means you want to keep it around as valid for some amount of time. Generally you retain at the point of assignment (either explicitly or by getting the reference via a Create function), and then you'd release it when the object is deallocated.
Crash is because may be you don't have strong ref (property) of myColor object. You might has assign property
Reason why [UIColor orangeColor] works but not [UIColor colorWithRed...
When you use [UIColor orangeColor], you don't create the object; you get a reference to it and something else manages its life cycle.
When you init a new UIColor object, you're responsible for making sure it is still valid when used. "assign" doesn't increase the object's reference count; "strong" does.
Hope it is helpful
EDIT
Decleare the one property like this
#property (nonatomic,strong) UIColor * myUIColor;
Now When you can
do this like
myUIColor =[UIColor colorWithRed:1.000 green:0.500 blue:0.000 alpha:1.000]
when you need CGColor
myUIColor. CGColor
Code Sample(iOS 8 Simulator & Xcode6):
-(void)viewDidLoad{
[super viewDidLoad];
UIColor *color = [UIColor whiteColor];
float a,b,c;
[color getRed:&a green:&b blue:&c alpha:nil];//Incompatible pointer types sending 'float *' to parameter of type 'CGFloat *' (aka 'double *')
}
I know that CGFloat is defined as double on 64 bit devices, but how could this cause crash?
The UIColor method will try to write a double to the memory pointed to by the parameters. This memory is declared as float instead of CGFloat (i.e. double). Not sure about the size of a a float on 64 bit machines, but my guess is that a float is smaller than double. So that method (getRed:green:blue:alpha) is writing into memory that is not owned by you (or the app, hence the bad access.
Also, as this method is expecting pointers (a C-concept), you should not pass nil, but NULL. Although they are both identical from a compiler's perspective, your intent and understanding is more clear when you are passing the correct type.
You are invoking undefined behaviour. Anything can happen, including a crash. Or a crash that will never happen on your machine, but every time Apple reviews your app. Or every time paying customers use your app.
You better check what warnings you have turned off that allow the compiler to compile this code, and turn them back on or turn them into errors.
I have a sound object that when played, it gets a timestamp set so that my application can prevent similar sounds from being played ontop of each other... The play method simply does:
self.timestamp = [[NSDate date] timeIntervalSince1970];
For some bizarre reason, I am experiencing this intermittently crashes my application when testing on an iPhone6...
malloc: *** error for object 0x1742059b0: Invalid pointer dequeued from free list
I am not sure 1) why this crash would happen, and 2) what can I do to prevent it?
If NSTimeInterval (AKA a double), the property attributes should be nonatomic (depending on if you want pseudo-thread safety) and assign. Retain/Strong/Weak/Copy are used for object types. Primitives such as BOOL and float/double/int etc. should be assign. Hope this helps!
This line of code works perfectly
[self explodeBomb:obj];
but if I replace it with the following line, I get an NSInvalidArgument Exception, with the reason being an unrecognized selector.
[self performSelector:#selector(explodeBomb) withObject:obj ];
The definition of the method is as follows:
-(void)explodeBomb:(SKNode *)bomb
I know, this has to be me not understanding something fundamental. But why I am able to call the method directly with no problems, but when I try to use the performSelector it blows up? For the record obj is defined as an ID. I tried changing the signature of explodeBomb to take an ID and then explicitly cast it inside the method, but that threw the same exception. Anyone know what the heck I am doing wrong?
Use : and write like below
[self performSelector:#selector(explodeBomb:) withObject:obj ];
Since your method explodeBomb has an argument so you have to specify :
I am trying to put a few CGImageRefs into an NSArray. It works as it should on the simulator, but not on the device - it crashes at the point where I try to form the array with a EXC_BAD_ACCESS code = 1 error. I tried other things too, like starting with a mutable array but it doesn't work either. The result of typing bt in the console is
(lldb) bt
* thread #1: tid = 0x2403, 0x3a9b25b6 libobjc.A.dylib`objc_msgSend + 22, stop reason = EXC_BAD_ACCESS (code=1, address=0x86ea78f7)
frame #0: 0x3a9b25b6 libobjc.A.dylib`objc_msgSend + 22
frame #1: 0x32a98b5e CoreFoundation`+[__NSArrayI __new:::] + 58
frame #2: 0x00042388 NameOfMyApp
So basically I have a number of images, of letters, and I have a number of layers representing positions in the word that should each cycle through them. For example, layer1 displays letterC, then letterF, then letterP etc, while layer2 displays some other sequence.
I thought I'd load each letter once...
CGImageRef letterH = [UIImage imageWithContentsOfFile:letterHfilename].CGImage;
CGImageRef letterI = [UIImage imageWithContentsOfFile:letterIfilename].CGImage;
...and put the CGImageRefs in an NSArray property, cast to id:
self.titleLetters = #[(__bridge id)letterH, (__bridge id)letterI;
I then later do
layerN.contents = self.titleLetters[i];
but more importantly I have to be able to put them (may times each) in ANOTHER array:
[contentsValuesArray addObject:self.titleLetters[j]];
and then use that array as the values of a keyFrameAnimation:
CAKeyframeAnimation* contentsAnim = [CAKeyframeAnimation animationWithKeyPath:#"contents"];
contentsAnim.values = contentsValuesArray;
All this works fine in the simulator, every time.
As I said, I tried some variations, and the only thing that seems to work is when I form a mutable array with just one letter-imageref in it, using arrayWithObject. Even then, it only works sometimes, and it crashes further down in my programme.
I seem to have read somewhere that the CGImageRefs are not retained, so that they may be released before I even get to use them. Since I began coding after ARC was introduced I know little about releasing, and since it has always worked on the simulator, I figured that didn't apply in my case.
Also, in this reply:
How do I create a mutable array of CGImageRefs?
a person working on Cocoa Frameworks says that it should work although he doesn't give any specifics, so it might be implied.
Any help and suggestions would be much appreciated.
EDIT SOLVED
It seems that the problem was indeed that the imagerefs did not exist when I tried to add them to the array, and this was because they had been released already. Apparently they need to be retained using CGImageRetain. It now works, I just need to make sure they are released afterwards.
The solution was that the imagerefs were being released before I even had time to use them. It seems this happens straight away (at least on the device), unless they are retained using CGImageRetain.