Array, memory management - objective-c

I have some code where I implemented undo functionality, the undo function is as follows:
- (void) undo
{
drawImage.image = pathArray.lastObject;
[pathArray removeLastObject];
}
Then I have one more function to capture the current image from the screen; in this function I am getting EXC_Bad_ACCESS error on this
[pathArray removeLastObjectatIndex:0];
No other calls of functions are made in this part of program. Maybe there could be a problem of moving whole array, but I don't want to use undo manager.
Is there any better way, to get the last object of an array and then remove the first one and move whole array by one?
Notice : path array is MutableArray *patharray;
Thanks all!=)
I just don't have and idea how to solve this. I didn't find any solution in the official docs.

Ultimately, this program would not likely be reachable -- It implies there is nothing to 'undo' in many contexts, and the option should not be given. Your problem often ultimately lies upstream.
If that is not quite the case here, here is one approach:
- (void)undo
{
if (0 == self.pathArray.count) {
self.drawImage.image = nil;
return;
}
self.drawImage.image = self.pathArray.lastObject;
[self.pathArray removeLastObject];
}
As well, [pathArray removeLastObjectatIndex:]; is not a real selector.
Update
See my answer here to enable and find zombies, and locate the reference count offset quickly. Your program should never message a zombie.

Related

How can I solve "Collection was mutated while being enumerated", #synrchonized, mutableCopy, or something else?

In Crashlytics, I'm seeing a crash that my users are experiencing quite infrequently. The offending code looks like this...
- (void)updateIsAnsweredField:(NSArray *)moduleItemsList
{
if (moduleItemsList && self.answeredItems && self.answeredItems.count > 0) {
for (ModuleItem * item in moduleItemsList) { // "Collection was mutated while being enumerated"
if ([item isKindOfClass:[ModuleItem class]] && [item shouldCheckIfAnswered]) {
item.answered = [self isAnsweredItem:item.moduleID];
}
}
}
}
The error given by Crashlytics can be seen in a comment in the code snippet above.
I assume there are a few ways to go about solving this.
1) wrap everything inside the function in #synchronized(moduleItemsList) {}. Is this the ideal way to solve? I've heard #synchronized is very slow and to avoid it when possible.
2) Create a copy a la NSMutableArray *copyModuleItemsList = [moduleItemsList mutableCopy];. Then enumerate that. Would this solve the issue? I would assume it would solve this particular issue, but there would be another problem no? That being... at the end when we go to assign our copy back to our original a la moduleItemsList = copyModuleItemsList;, moduleItemsList may have changed in the meantime on a different thread.
3) Trace the passed in :(NSArray *)moduleItemsList to whomever holds it as a property. Then overwrite the getter to use dispatch_sync, and the setter to use dispatch_barrier_async. However, there is no guarantee that the original array is a property of any class whose getter and setter can be overridden. And actually, none of this makes sense since we wouldn't be specifically changing that array would we?
I'm a bit confused. Can anyone assist in this matter? Is #1 the option I want?
EDIT: Adding more code
[item shouldCheckIFAnswered]:
This just checks a #property value that exists on the ModuleItem class. if self.moduleType == ModuleTypeSuchAndSuch
isAnsweredItem::
- (BOOL)isAnsweredItem:(NSString *)moduleID
{
if (!self.answeredItems) {
return NO;
}
return [self.answeredItems containsObject:moduleID];
}
From your post, it sounds like the moduleItemsList is getting modified in another thread. The "correct" way to fix this is going to depend on what the desired relationship between the state in the other thread and the state in this thread is.
If you use #synchronized(moduleItemsList) in both this code, and in the code that modifies the collection in the other thread, then when this code runs, it'll always have an "up to date" view of moduleItemsList.
If you copy the moduleItemsList into another object, then when this code runs, it might set the answered value on an item that's no longer in the moduleItemsList, or it might fail to set the answered flag on an item that was recently added to moduleItemsList.
In general, the #synchronized version is the easier way to get "correct" behavior. You'd only want to use copy if you're sure that it doesn't matter that the two threads may disagree about the current contents of moduleItemsList.
I've heard #synchronized is very slow and to avoid it when possible.
This is terrible advice, in general. #synchronized is just as slow as it needs to be to ensure consistent state between threads, and to provide a re-entrant lock. You don't want to just throw #synchronized around everything, willy-nilly, but it's a fine solution to synchronizing data access between threads - that's what it's for, after all.

Required Methods for Text Changes in Custom NSTextView

I have a custom NSTextView, and I want to be sure to send all of the proper messages and notifications when making changes to the text programmatically. I mostly care about undo/redo registration, but I'd generally like to do things the "right" way. Anyway …
The messages I'm aware of are:
-shouldChangeTextInRange:replacementString:
-didChangeText
If I understand the documentation correctly, before any changes are made to the text view's textStorage object, one needs to send the -shouldChangeTextInRange:replacementString: message to make sure a new undo group is opened (and inform any delegates of the commencement of editing). If YES is returned, the changes can be made to the text. Once all of the changes have been applied, the -didChangeText message needs to be sent to close the undo group (and again, notify any observers). Is this right?
When modifying existing characters (or attributes) those instructions make sense to me. I'm acting on an existing range of text, so it's easy to know what to send for the affectedCharRange parameter. What about when I need to insert something?
Let's say I want to insert a random word at the current insertion point index. Do I need to send the -shouldChangeTextInRange:replacementString: message? I'm not modifying existing characters, but I am adding new characters to the existing characters.
If I do need to send this message, what range do I use for the affectedCharRange argument? Whenever I try to send the new computed range of the to-be-inserted text, I get "Range Out of Bounds" errors, which makes sense, considering the text view's length has yet to change. Do I just send the range for the insertion point with an empty length (e.g. self.selectedRange when nothing's selected)?
For example:
- (void)insertRandomWord:(id)sender
{
NSAttributedString *randomAttrStr = [self randomAttributedString];
BOOL shouldChangeText = [self shouldChangeTextInRange:shouldThisBeTheSelectedRange // <-- WTF, mate?
replacementString:randomAttrStr.string];
if ( shouldChangeText ) {
[self.textStorage insertAttributedString:randomAttrStr
atIndex:self.selectedRange.location];
// This should always get called, right?
[self didChangeText];
// Is this where I would set the typing attributes?
self.typingAttributes = [randomAttrStr attributesAtIndex:0 effectiveRange:NULL];
}
}
I've gone as far as to create a method that takes a range and a block as arguments, so I don't accidentally forget to call something. Is this a good idea or not?
- (void)changeTextInRange:(NSRange)range replacementString:(NSString *)replacementString usingBlock:(void (^)(void))block
{
BOOL change = [self shouldChangeTextInRange:range replacementString:replacementString];
if ( change ) {
block();
[self didChangeText];
}
}
Last, but not least, do I need to call the NSTextStorage "editing" methods, too? The methods I'm referring to are:
-beginEditing:
-endEditing:
The documentation discusses calling those when one subclasses NSTextStorage, but I'm a little confused as to whether those messages need to be sent, too. It doesn't really say whether or not to use -fixAttributesInRange:, but I know the -endEditing message calls that to do cleanup after an editing operation.
I apologize for the discombobulated mess of questions. I'm just super tired and confused, and Apple's documentation has been … lacking. Any tips, pointers, and/or suggestions would be greatly appreciated. Thanks!

Override setter in Objective-c. Why check is equal parameter

Often find custom setter sintaxis like this:
- (void)setParentCatalog:(Catalog *)parentCatalog {
if (_parentCatalog != parentCatalog) { //???
_parentCatalog = parentCatalog;
[self refresh];
}
}
Why i should check?
if (_parentCatalog != parentCatalog)
This checks if both _parentCatalog and parentCatalog are pointing to the same memory location.
If both are same object then no need to set the objectValue.
The reason for checking if the two are equal is to avoid executing code when it's not necessary. If the method is called very often, this could have a performance benefit. Under non-ARC, your code might look more like this:
- (void)setParentCatalog:(Catalog *)parentCatalog {
if (_parentCatalog != parentCatalog) {
[_parentCatalog release];
[parentCatalog retain];
_parentCatalog = parentCatalog;
[self refresh];
}
}
So, by checking that what you received is actually a new value, you avoid those retain and release calls happening (which are still there with ARC). You've also got [self refresh] in there, which probably doesn't need to happen unless the value has actually changed.
The idea here is that if the parameter passed in to the setter is the same object already stored in the property, then there is no need to call [self refresh] again.
A refresh method often reads in data, works on it and then re-displays it in the app's views. No need to do all this work again if the data in the property haven't really changed.
It's a decision that is use case dependant. The idea behind this guard is to prevent doing unnecessary work.
If you imagine that your [self refresh] kicked off a very expensive operation then you would be reluctant to do it every time. So if you only do it when the object actually changes you save yourself some work.
Of course this may well be the behaviour you are looking for in which case you would need to stick the [self refresh] call outside of the guard.
Like all code examples you find it's worth weighing up the trade offs of the implementation and then you can better decide what you need in your case.

What is the need for a primitive when using a transient property?

What is it?
I'm not sure I quite understand what this does.
- (NSString *)sectionIdentifier {
[self willAccessValueForKey:#"sectionIdentifier"];
NSString *tmp = [self primitiveSectionIdentifier];
[self didAccessValueForKey:#"sectionIdentifier"];
if (!tmp) {
tmp = #"bananas";
[self setPrimitiveSectionIdentifier:tmp];
}
return tmp;
}
How come I need this primitiveSectionIdentifier?
Ultimately, I'm using a example project from Apple's documentation to create a section identifier, to use with my NSFetchedResultsController.
While this does work. I am saying to myself that,
"sectionIdentifier" will be accessed,
then I'm setting "tmp" to primitiveSectionIdentifier. But primitiveSectionIdentifier has nothing there at this point!! Does it?
I then say I did access "sectionIdentifier". But I can't see how that happened between "Will" and "Did"!
Can someone help me understand this?
[self primitiveSectionIdentifier] is a so-called "primitive accessor" (see the Glossary of the Core Data Programming Guide). That is the function that actually fetches the value of the "sectionIdentifier" from the persistent store. The function is automatically created by the Core Data runtime.
willAccessValueForKey and didAccessValueForKey are "notification methods". According to the documentation, they are used for key-value observing, maintaining inverse relationships and so on.
So the pattern is:
Tell everybody that you are going to read a value.
Read the value.
Tell everybody that you have read the value.

What does NSLog actually do?

I am having a weird problem. I am using a method from Apple's private frameworks in my application. When I call it for the first time, it works. When I call it for the second time immediately without anything in between, it crashes. However, if I put NSLog between the two calls, it works wonderfully. So I try removing NSLog and puting for-loops, sleep(), printf("..."), and fprintf(stderr, "...") between them to emulate NSLog, but it doesn't help. I am wondering how the method knows that I use NSLog? In other words, what does NSLog actually do to affect the behaviors of the method?
Thank you very much!
EDIT:
I seem to solve this problem. I will share my solution here and hope it may be useful to some people.
I am creating a multitouch-related application using MultitouchSupport.framework. I copied code from http://aladino.dmi.unict.it/?a=multitouch and added a CFRelease at the end of the loop. So, basically, my main method looks like this :
int main(void) {
int i;
NSMutableArray* deviceList = (NSMutableArray*)MTDeviceCreateList(); //grab our device list
for(i = 0; i<[deviceList count]; i++) { //iterate available devices
MTRegisterContactFrameCallback([deviceList objectAtIndex:i], touchCallback); //assign callback for device
MTDeviceStart([deviceList objectAtIndex:i], 0); //start sending events
}
CFRelease((CFMutableArrayRef)deviceList);
printf("Ctrl-C to abort\n");
sleep(-1);
return 0;
}
After running for a while, it will show "Program received signal: “EXC_BAD_ACCESS”."
And here is the stack trace:
#0 0x7fff8795496e in ParsedMultitouchFrameRepInitialize
#1 0x7fff879565b1 in mt_HandleMultitouchFrame
#2 0x7fff87955a03 in mt_DequeueDataFromDriver
#3 0x7fff87955b29 in mt_DequeueMultitouchDataFromDriverThreadEntry
#4 0x7fff831b3456 in _pthread_start
#5 0x7fff831b3309 in thread_start
However, if I put NSLog below MTDeviceStart, it will not crash.
The reason I added CFRelease((CFMutableArrayRef)deviceList) to the original code is that I think objects that are created from functions named *Create* or *Copy* should be released by ourselves. But it turns out that if I remove it like the original code does, it will not crash, even without using NSLog.
So, maybe it's because I release deviceList too early? But if that's so, why does NSLog seem to be able to prevent the crash?
Something similar to this:
static inline void NSLogMessageString(NSString *string){
NSString *date=[[NSDate date]
descriptionWithCalendarFormat:#"%Y-%m-%d %H:%M:%S.%F"
timeZone:nil locale:nil];
NSString *process=[[NSProcessInfo processInfo] processName];
NSLogFormat(#"%# %#[%d:%lx] %#",date,process,NSPlatformProcessID(),NSPlatformThreadID(),string);
}
void NSLogv(NSString *format,va_list arguments) {
NSString *string=NSStringNewWithFormat(format,nil,arguments,NULL);
NSLogMessageString(string);
[string release];
}
void NSLog(NSString *format,...) {
va_list arguments;
va_start(arguments,format);
NSLogv(format,arguments);
}
Thanks for asking this question lol, I wanted to rewrite it so I could add debugging variables, meaning I could turn all NSLogging calls off when needed..
It takes a long time. I'm not sure why. It prints the date/time, process name, process ID, thread ID, and (finally) the string you asked for. I think it also sends the log message to syslogd (either Xcode or iPCU's console shows multiline NSLogs as a single entry; I forget which); the IPC there might be significant.
Try using syslog() (#import <syslog.h> and then syslog(LOG_INFO, "Hello there!");, if it works but you get no output, try changing the priority (see man 3 syslog).
NSLog can affect issues like the one you are running into because it affects the order that threads execute because when you call NSLog in a background thread, it has to gain exclusive access to stdout. printf debugging tricky problems with threads often leads to "heisenbugs" for this reason (i.e. they change behavior when you try to examine them).
It could be a problem with memory management: an extraneous release perhaps. If you post the traceback, it might be some help in tracking down the issue. (As it turns out, someone on Twitter I follow mentioned something like this last night).