1

I'm looping through the results of a fetch request against a Core Data store. For each object in the result list, I am reading several attributes of type string and concatenating them into one string (to be output as a CSV format file).

One particular string of one particular record in my dataset is giving me trouble: extraneous characters (kanji, arabic, etc.) are appended to the end of the string, it does not append properly to my result string, and my CSV file format is hosed.

Here is my code for looping through the fetch results and appending the string:

NSMutableString *reportString = [[NSMutableString stringWithFormat:@"...\n"];
for (int s = 0; s < [frc.sections count]; s++) {
    for (int r = 0; r < [[frc.sections objectAtIndex:s] numberOfObjects]; r++) {
        NSIndexPath *i = [NSIndexPath indexPathForRow:r inSection:s];
        Thread *thread = [frc objectAtIndexPath:i];
        NSMutableString *activity = [NSMutableString stringWithString:[thread activity]];
        .
        .
        .
        [reportString appendString:activity];
        [reportString appendFormat:@",%@\n", client];
    }
}

I'm using stringWithString here, but I've also used several other string methods with similar, corrupted, results. One time, Arabic letters appeared. Another time, it was "...random...FSO_CARRIER_ATT@2X.png". I've also tried using a separate fetch results array (instead of a fetched results controller).

"Corrupted" String

One weird thing is that when I do a PO from lldb, the string shows up correctly. This may explain why this "corruption" doesn't show up on my table views, just when I am trying to mash strings together.

My Question

Am I copying the string values from the Core Data model incorrectly and causing this to happen? Is there a technique I am missing out on?

Update:

A screenshot of the watched variable versus an NSLog of the value:

screnshot 2

Community
  • 1
  • 1
Anthony C
  • 1,990
  • 3
  • 23
  • 40
  • What data type has the activity attribute of the Thread entity? – Martin R Apr 04 '13 at 09:06
  • [Thread activity] is a NSString. – Anthony C Apr 04 '13 at 09:17
  • I can't see an obvious error in your code. What does NSLog of `[thread activity]` and `[[thread activity] class]` show? Is `activity` modified in the ". . ." part? – Martin R Apr 04 '13 at 09:25
  • I'll try an NSLog to see what it says. I have been doing a PO in lldb - that prints out the expected value. But the watch pane and the end result show them to not be true. ...and *activity* is never modified here. – Anthony C Apr 04 '13 at 09:27
  • The NSLog shows the same thing as PO - the correct value. Yet at the same time, the debugger watch shows the extra characters. (I'll attach another screenshot.) – Anthony C Apr 04 '13 at 09:34
  • (btw, thank you for taking the time) – Anthony C Apr 04 '13 at 09:35
  • Is this only a possible Xcode/debugger problem or is `reportString` actually corrupted at some point? If it is: can you isolate the point where that happens? – Martin R Apr 04 '13 at 09:54
  • reportString is indeed corrupted, and by this statement. That was how I started down this path. reportString is built correctly when I select other records in my database. When I selected this one, I had problems. (move this to chat?) – Anthony C Apr 04 '13 at 10:00
  • I can imagine a few situations for which this might be happening. First make sure that your .xcdatamodel reflects a string type your Thread entity, activity attribute. Secondly, are you accessing this information in some kind of thread or block? It could very well be a racing condition. Are you accesing it in the main thread? Are there any other threads that may be accessing it concurrently? Why don't you try to @syncronize that section of the code to guarantee mutual exclusion? – Javier Quevedo Apr 04 '13 at 10:57
  • Why is `activity` a mutable string? Are you changing its contents somewhere in the deleted lines? If so, how? – Tom Harrington Apr 04 '13 at 16:50
  • @sEnC: This is happening in the main thread, modal view controller. Thanks for the ideas, I’ll try to make sure nothing is stepping on it. – Anthony C Apr 04 '13 at 19:05
  • @Tom: it’s set as mutable just as an attempt to see why it wasn’t working. It doesn’t get changed. It was originally NSString and I got the same issue. – Anthony C Apr 04 '13 at 19:06
  • I may have found the cause for this strange behaviour. I use curly apostrophes in my text entries where appropriate. I'll have to double-check my encodings. (related to this: http://stackoverflow.com/questions/4797574/iphone-nsmutableurlrequest-returns-strange-characters-for-ms-word-style-apostro) – Anthony C Apr 08 '13 at 18:29

2 Answers2

1

As I mentioned in the comments, this turns out to have been a string encoding/decoding issue.

I formulated a more directed question (How do I properly encode Unicode characters in my NSString?) and got the answer very quickly.

Basically, I was using the proper string manipulation methods, as everyone here agreed. In the end, the encoding parameter I was using to attach the CSV file to the email was incorrect. At the same time, the discrepancy between the variables pane and the lldb pane in Xcode appears to be a legitimate bug. I'll be filing a bug report for that one.

Community
  • 1
  • 1
Anthony C
  • 1,990
  • 3
  • 23
  • 40
-1

I would put this whole iteration code into one serial background thread. The corruption of the order of your input has certainly to do with the threads competing against each other. You can still use separate threads, but you have to make sure they are executed serially, i.e. that one thread waits for previously scheduled threads to finish.

In Grand Central Dispatch, this would be a thread like

dispatch_queue_t serialThread = 
   dispatch_queue_create("serialThread", DISPATCH_QUEUE_SERIAL); 

You could also use the managed object context with

[context performBlockAndWait:...];
Mundi
  • 79,884
  • 17
  • 117
  • 140
  • Actually, I'm not sure how I would go about taking your advice. The app is running on just one thread, the main one. So, as far as I know, there aren't multiple threads competing with each other. This loop is taking place just before the presentation of a modal view controller that uses the data, so everything is waiting on it. (Unless iOS is putting it in a background thread I don't know about?) – Anthony C Apr 04 '13 at 20:01
  • My next idea is that it has to do with the encoding. Could you please tell us exactly what happens? It seems that the string "client" is appended to the end of line correctly. – Mundi Apr 05 '13 at 06:55
  • Please let me know what information you need. What do you mean by encoding and "what exactly happens"? Not sure if I understand what you are looking for. Basically, the loop goes around and at one point (the same record), the dirty data shows up in the debugger. This coincides with the csv file not forming properly. (As opposed to other times when the dirty data does not appear and the csv file is ok.) – Anthony C Apr 05 '13 at 07:12
  • Please more in detail: you get a string from your thread object. You append it to the mutable string for the csv. At which point does something unexpected happen? What exactly is wrong? ("dirty data" is too vague). – Mundi Apr 05 '13 at 07:20
  • I only said "dirty data" within this comment thread. By that, I meant what is described in the main question, quoted from above: "corrupted, results. One time, Arabic letters appeared. Another time, it was "...random...FSO_CARRIER_ATT@2X.png"." I also included screenshots from the debugger. The point at which the unexpected happens is when I copy the Core Data object's attribute into a string and unwanted characters appear at the end. If there is something other than this information that can help you answer my problem, please let me know. – Anthony C Apr 05 '13 at 07:44
  • Maybe you can encapsulate the problem: log thread.activity; then log the string you create. Make sure one occurs exactly after the other. If the error occurs there, try allocating an new string with alloc init. If there is no error there, the corruption happens somewhere else. – Mundi Apr 05 '13 at 08:16