What's calling CFStringCreateFromExternalRepresentation? - objective-c

I'm rather confused by this stack trace (only the confusing part is shown):
-[NSXMLDocument length]: unrecognized selector sent to instance 0x10187e010
An uncaught exception was raised
-[NSXMLDocument length]: unrecognized selector sent to instance 0x10187e010
(
0 CoreFoundation 0x00007fff8f5d6286 __exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff9213bd5e objc_exception_throw + 43
2 CoreFoundation 0x00007fff8f6624ce -[NSObject doesNotRecognizeSelector:] + 190
3 CoreFoundation 0x00007fff8f5c3133 ___forwarding___ + 371
4 CoreFoundation 0x00007fff8f5c2f48 _CF_forwarding_prep_0 + 232
5 CoreFoundation 0x00007fff8f548c66 CFDataGetLength + 118
6 CoreFoundation 0x00007fff8f5791df CFStringCreateFromExternalRepresentation + 31
7 asLJ 0x0000000100013828 +[stripHTML stripAllHtmlFromString:] + 212
In particular, I don't understand where the call to CFStringCreateFromExternalRepresentation is happening, so I don't know what part of my code (+[stripHTML stripAllHtmlFromString:]) is causing the exception. What's causing the call to CFStringCreateFromExternalRepresentation? If it's obvious, what is it that I'm doing wrong that's causing the exception? In the future, how can I go about determining what's calling CFStringCreateFromExternalRepresentation?
Here's +[stripHTML stripAllHtmlFromString:]:
+ (NSString *)stripAllHtmlFromString:(NSString *)inputString
{
// based on code from http://sugarmaplesoftware.com/25/strip-html-tags/#comment-71
NSError *theError = NULL;
NSString *modifiedInputString = [NSString stringWithFormat:#"%#\n\n\n\n\n\n\n\n\n\n\n\n",inputString]; // adding some spare newlines at the end to ensure that things will work even with a short non-HTML string
NSXMLDocument *theDocument = [[NSXMLDocument alloc] initWithXMLString:modifiedInputString
options:NSXMLDocumentTidyHTML
error:&theError];
NSString *theXSLTString = #"<?xml version='1.0' encoding='utf-8'?>"
"<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform' xmlns:xhtml='http://www.w3.org/1999/xhtml'>"
"<xsl:output method='text'/>"
"<xsl:template match='xhtml:head'></xsl:template>"
"<xsl:template match='xhtml:script'></xsl:template>"
"</xsl:stylesheet>";
NSData *theData = [theDocument objectByApplyingXSLTString:theXSLTString arguments:NULL error:&theError];
[theDocument release];
return [[[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding] autorelease];
}

Oh, actually, probably -objectByApplyingXSLTString:arguments:error: returned an NSXMLDocument and not an NSData. So, the call to -[NSString initWithData:encoding:] is invoking -length on what it thinks is an NSData, but NSXMLDocument doesn't recognize that.

Ken Thomases's answer seems to have it exactly right—for some reason, for very short input (particularly the empty string), -objectByApplyingXSLTString:arguments:error: with the given XSLT returns an NSXMLDocument (even though I don't think it should). To fix it, I first detect whether we got an NSXMLDocument and if so, turn it into a string representation of the XML and feed that back into the method; otherwise assume we got the NSData that we'd originally expected.
Replacing the last 3 lines of the given method (from NSData *theData =... on) with the code below seems to have fixed the issue.
// Had a report of an exception that seemed to indicate objectByApplyingXSLTString:arguments:error: was returning an NSXMLDocument objectinstead of an NSData object, so let's guard against that. (discussed at https://stackoverflow.com/q/10669479/291280 )
NSObject *XSTLresult = [theDocument objectByApplyingXSLTString:theXSLTString arguments:NULL error:&theError];
[theDocument release];
if ([XSTLresult isKindOfClass:[NSXMLDocument class]]) {
// If the result is an NSXMLDocument, call XMLData to get an NSData object, turn it into a string, and feed that back into this method...
return [self stripAllHtmlFromString:[[[NSString alloc]
initWithData:[(NSXMLDocument *)XSTLresult XMLData]
encoding:NSUTF8StringEncoding]
autorelease]
];
} else {
// Otherwise, assume we have an NSData object.
return [[[NSString alloc] initWithData:(NSData *)XSTLresult encoding:NSUTF8StringEncoding] autorelease];
}

Related

Creating generic Objective C relationship model

I'm trying to setup generic model for retrieving data from a backend and processing the data in my iPhone app. I'm trying to accomplish this by creating a base-class for all class in which all logic is defined for retrieving, saving and linking data. This last part is the part I'm struggling on.
In every class I define the object name (in Core Data) and if a certain object has relationships to other objects, also and array of the names of the objects with two arrays (one for hasOne and one for hasMany).
However I can't seem to accomplish cast retrieved objects to a certain class which is stored as a string. This is the code I currently have:
/**
Update the relationsships of an object which has relationsships from the type 'HasOne'.
#param object
Object from which the relations has to be updated.
*/
- (void)updateRelationshipsHasOne:(id)object {
for(NSString *relation in self.hasOne) {
Class class = NSClassFromString(self.table);
id anInstance = [class alloc];
anInstance = object;
NSString *key = [[NSString alloc] initWithFormat:#"%#_id",[relation lowercaseString]];
id delegata = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [delegata managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:relation inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat: #"db_id == %i",[[object valueForKey:key] intValue]];
[fetchRequest setPredicate:predicate];
NSError *error;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if(fetchedObjects && [fetchedObjects count] > 0) {
id otherInstance = [fetchedObjects objectAtIndex:0];
SEL s = NSSelectorFromString([[NSString alloc] initWithFormat:#"set%#",relation]);
[anInstance performSelector:s withObject:otherInstance];
}
}
}
If I cast both 'anInstance' and 'otherInstance' to the desired classes, everything goes well. However the whole purpose is to make the method generic, so I need some way to be able to cast both variables to Classes which are stored as strings.
Thanks a lot in advance for any help!
Edit:
The error message I'm receiving is:
2016-03-21 20:34:19.024 DeDamen[12303:834645] -[Heat setEvent]: unrecognized selector sent to instance 0x7fe2829d8cd0
2016-03-21 20:34:19.026 DeDamen[12303:834645] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Heat setEvent]: unrecognized selector sent to instance 0x7fe2829d8cd0'
*** First throw call stack:
(
0 CoreFoundation 0x0000000109e68e65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x00000001094c0deb objc_exception_throw + 48
2 CoreFoundation 0x0000000109e7148d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x0000000109dbe90a ___forwarding___ + 970
4 CoreFoundation 0x0000000109dbe4b8 _CF_forwarding_prep_0 + 120
5 ******* 0x0000000105d255ab -[CommonBase updateRelationshipsHasOne:] + 1627
6 ******* 0x0000000105d24e60 -[CommonBase updateRelationships:] + 256
7 ******* 0x0000000105d248a9 -[CommonBase save:handler:] + 1065
****
)
libc++abi.dylib: terminating with uncaught exception of type NSException
In here the model 'Heat' refers to the object 'anInstance' and the model 'Event' refers to the object 'otherInstance'. The relations ship is: a Heat has one Event and an Event has many Heats'

Segmentation fault - performSelectorOnMainThread on [NSFileManager defaultManager]

This code seems to be causing a segmentation fault from time to time:
[[NSFileManager defaultManager] performSelectorOnMainThread:#selector(removeItemAtPath:error:) withObject:filePath waitUntilDone:YES];
I want to perform all operations on files in the main thread to avoid conflicts like removing a file while the whole folder is iterated.
It produces this error:
Exception Type: SIGSEGV
Exception Codes: SEGV_ACCERR at 0x1084
Application Specific Information:
objc_msgSend() selector name: release
This is the stack trace of the crashed main thread:
Thread 0 Crashed:
0 libobjc.A.dylib 0x39fc8636 objc_msgSend + 22
1 Foundation 0x30214c67 __NSThreadPerformPerform + 452
2 CoreFoundation 0x2f7f6fef __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 12
3 CoreFoundation 0x2f7f64b7 __CFRunLoopDoSources0 + 204
4 CoreFoundation 0x2f7f4ca7 __CFRunLoopRun + 628
5 CoreFoundation 0x2f75f769 CFRunLoopRunSpecific + 522
6 CoreFoundation 0x2f75f54b CFRunLoopRunInMode + 104
7 GraphicsServices 0x346bc6d3 GSEventRunModal + 136
8 UIKit 0x320be891 UIApplicationMain + 1134
9 Pocket3 0x00050243 main (main.m:4)
10 libdyld.dylib 0x3a4bcab7 start + 0
What am I doing wrong?
It looks like the NSFileManager is deallocated too early, but how can it be if it is a singleton?
Could it have something to do with the method [NSFileManager defaultManager] which is said to not be thread safe?
Update: new answer
NSFileManager is threadsafe (as long as you are not using its delegate, which you don't, and which you shouldnt do with the -defaultManager anyways). You can just call [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error] on whatever thread you are currently on. There is no advantage on doing it on the main thread only. In fact, performance will probably better if you update the filesystem in a background thread, because the UI will not block if the operation takes longer than expected.
Old answer (why the crash did happen)...
The method -removeItemAtPath:error: wants two objects, but you are providing only one. So the second paramter (NSError **) that the -removeItemAtPath:error: method will see, is just some garbage that lies next to the filePath pointer in memory.
There is no version of -performSelectorOnMainThread:... that takes two objects. You may use dispatch_sync instead:
dispatch_sync(dispatch_get_main_queue(), ^() {
NSError *error = nil;
BOOL ok = [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
if(!ok) {
NSLog(#"an error happened: %#", error);
}
}

JSON request error [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I'm experimenting with JSON for the first time in Objective-C.
Here's the code for my Terminal Application:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"https://itunes.apple.com/search?term=harry&country=us"]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSError *jsonParsingError = nil;
NSArray *publicTimeline = [NSJSONSerialization JSONObjectWithData:response options:0 error:&jsonParsingError];
NSDictionary *list;
for(int i=0; i<[publicTimeline count];i++)
{
list = [publicTimeline objectAtIndex:i];
NSLog(#"Statuses: %#", [list objectForKey:#"trackName"]);
}
}
return 0;
}
Here's the error I'm getting:
2013-09-11 20:58:55.524 Tweets[7291:303] -[__NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0x100391d60
2013-09-11 20:58:55.526 Tweets[7291:303] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0x100391d60'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff91688b06 __exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff8bf8a3f0 objc_exception_throw + 43
2 CoreFoundation 0x00007fff9171f40a -[NSObject(NSObject) doesNotRecognizeSelector:] + 186
3 CoreFoundation 0x00007fff9167702e ___forwarding___ + 414
4 CoreFoundation 0x00007fff91676e18 _CF_forwarding_prep_0 + 232
5 Tweets 0x0000000100000d1a main + 378
6 libdyld.dylib 0x00007fff908e67e1 start + 0
)
libc++abi.dylib: terminate called throwing an exception
What's wrong? I have followed a tutorial perfectly but I am the only one getting the error.
I ran your code. My results didn't agree with yours. I didn't crash, but I did receive (null) from the final NSLog call.
Yes, you should be checking the result of +[NSJSONSerialization JSONObjectWithData:options:error]. As #HotLicks has pointed out to you quite rightfully, if the result you get is nil, examining the error object can reveal important clues as to what's gone wrong.
But in this case, it's academic because the result (again, in my case) wasn't nil. The real problem, however, is that you don't appear to have an understanding of your data's schema. jsonObject is a dictionary, but it has only two keys, results and resultCount, and that's the reason you're getting nil from [jsonObject objectForKey:#"trackName"]; trackName isn't one of the keys.
Those two keys that you do get, however, should tell you plenty. It told me enough to try this:
NSArray *results = [jsonObject objectForKey:#"results"];
NSDictionary *dictionary = [results objectAtIndex:0];
id latestLoans = [dictionary objectForKey:#"trackName"];
and got a result:
Harry Potter and the Deathly Hallows - Part 1
In other words, I simply got the first dictionary in the array for results, and asked it for the object it had for trackName.
Since you were originally asking for an array, I'm guessing that you wanted all the values for that particular key, so if you use this:
NSArray *latestLoans = [jsonObject valueForKeyPath:#"results.trackName"];
it provides a list of 50 values corresponding to the trackName key in the dictionaries under the results key.
EDIT:
One other thing you really need to do is to protect yourself against the possibility of nil being returned from your call to -[NSData initWithContentsOfURL:] by checking for it before calling anything else. This alone won't fix your inability to get a response, but it will keep you from crashing. And if you do receive nil, be sure to check the domain and code properties of the error object you get back to get an idea of what's going wrong.

Two NSFetchedResultsController, Two Views, One Entity-Type

I'm currently banging my head around this problem:
I have two views on the same entity. The first one lets the user CRUD the Entity (TouchModelVariable), the second one lets the user assign it to a another entity (TouchModelConstraintTerm). The second view is only for selection. But when I delete entities via the first view, upon scrolling in the second view the app crashes with an "index out of bounds" error.
Detailed explanation: First the first controller, the CRUD one.
MSPUIManagedDocument *doc = self.document;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:MODEL_ENTITY_TOUCH_MODEL_VARIABLE inManagedObjectContext:doc.managedObjectContext];
fetchRequest.entity = entityDescription;
fetchRequest.fetchBatchSize = 20;
//[NSComparisonPredicate predicateWithLeftExpression:[NSExpression expressionForKeyPath:#"touchModel.active"] rightExpression:[NSExpression expressionForConstantValue:YES] modifier:NSDirectPredicateModifier type:nil options:nil];
// touchModel.active == 1
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"touchModel == %#", self.touchModel, nil];
NSSortDescriptor *sortDescriptior = [NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES selector:#selector(caseInsensitiveCompare:)];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptior];
fetchRequest.sortDescriptors = sortDescriptors;
// nameSectionIndex
NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:doc.managedObjectContext sectionNameKeyPath:#"name" cacheName:#"MSPVariablesManagementTableViewController"];
fetchedResultsController.delegate = self;
NSError *error = nil;
[NSFetchedResultsController deleteCacheWithName:#"MSPVariablesManagementTableViewController"];
if(![fetchedResultsController performFetch:&error]) {
NSLog(#"Error while fetching <%#>, <%#>", error, [error userInfo]);
}
return fetchedResultsController;
The TableView is bound to that controller, as it's described in the book "Pro CoreData for iOS".
The second view uses nearly the same code, but the CacheKeys are different. If I delete entities with the first view, and then navigate through the app to the second view (which is re-instantiated every time) the app crashes upon scrolling, because it assumes that the deleted records are there.
I also tried to save the ManagedObjectContext, before entering the second view.
CRASH: *** -[_PFArray objectAtIndex:]: index (8) beyond bounds (8)
2012-03-17 11:36:48.953 MSPLPSolve[38685:fb03] Stack Trace: (
0 CoreFoundation 0x0192503e __exceptionPreprocess + 206
1 libobjc.A.dylib 0x01dc2cd6 objc_exception_throw + 44
2 CoreFoundation 0x018cda48 +[NSException raise:format:arguments:] + 136
3 CoreFoundation 0x018cd9b9 +[NSException raise:format:] + 57
4 CoreData 0x003ffc23 -[_PFArray objectAtIndex:] + 131
5 CoreData 0x004ec260 -[NSFetchedResultsController objectAtIndexPath:] + 448
6 MSPLPSolve 0x0005d820 -[MSPUtilitiesVariablesSelectionTableViewController configureCell:cellForRowAtIndexPath:] + 128
7 MSPLPSolve 0x0003057b -[MSPFetchedResultsTableViewController tableView:cellForRowAtIndexPath:] + 283
8 UIKit 0x008efc54 -[UITableView(UITableViewInternal) _createPreparedCellForGlobalRow:withIndexPath:] + 494
9 UIKit 0x008f03ce -[UITableView(UITableViewInternal) _createPreparedCellForGlobalRow:] + 69
10 UIKit 0x008dbcbd -[UITableView(_UITableViewPrivate) _updateVisibleCellsNow:] + 1350
11 UIKit 0x008ea6f1 -[UITableView layoutSubviews] + 242
12 UIKit 0x00893d21 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 145
... a load of other stuff not in my code ...
BUT when I save the document completly (closing, reopening) between deleting entities via the first controller and navigating to the second controller - it doesn't crash. Is NSFetchedResultsController caching a loads of stuff in the background? And is there a in depth guide how the caching works and how I have to use it?
Puuuh, thanks for reading this far! Regardless if you have an idea or not!
Mark
Did you do a performFetch on your results controller after you altered the model? Also I'm assuming your results controllers delegate methods are implemented correctly.

NSURLRequest autorelease: crash

I am having problem releasing NSMutableURLRequest object.
Application crashes during the deallocation of request object.
The object is created via [[NSMutableURLRequest alloc] initWithURL:my_http_url];
As mainstream flow of control, I try to release the connection object in response to connectionDidFinishLoading handler being invoked.
At first I tried autoreleasing NSMutableURLRequest right inside connectionDidFinishLoading handler. This caused crashing, so I assumed it might be because connection class pushes autorelease pool internally before calling connectionDidFinishLoading and still expects connection object to be valid when the handler returns, so it is impossible then to release or autorelease the connection object inside connectionDidFinishLoading.
If I do not release NSMutableURLRequest at all, according to Instruments it leaks with reference count 1.
Therefore I decided to do a delayed release via firing an NSRunLoop event that autoreleases NSMutableURLRequest passed to it.
This still causes a crash.
retainCount before calling autorelease is 1.
Crash stack is:
#
0 0x9448aedb in objc_msgSend
#1 0x04a47ce0 in ??
#2 0x02e51501 in HTTPMessage::~HTTPMessage
#3 0x02945621 in _CFRelease
#4 0x02e516a9 in HTTPRequest::~HTTPRequest
#5 0x02e50967 in URLRequest::~URLRequest
#6 0x02945621 in _CFRelease
#7 0x0032fb70 in -[NSURLRequestInternal dealloc]
#8 0x0032fb1a in -[NSURLRequest dealloc]
#9 0x002f27a5 in NSPopAutoreleasePool
#10 0x003b5dd0 in __NSFirePerformTimer
#11 0x0299e8a2 in __CFRunLoopDoObservers
#12 0x0296a39e in CFRunLoopRunSpecific
#13 0x0296a048 in CFRunLoopRunInMode
#14 0x031d289d in GSEventRunModal
#15 0x031d2962 in GSEventRun
#16 0x0058ede1 in UIApplicationMain
#17 0x00002b9c in main at main.m:14
Thanks for advise.
After using NSDebugEnabled/NSZombieEnabled/NSAutoreleaseFreedObjectCheckEnabled I identified the problem:
result of
http_url = [NSURL URLWithString:...]
should have been either retained or not autoreleased on its own.
Try to instantiate it as an autoreleased object using:
[NSMutableURLRequest requestWithURL:my_http_url];
I believe Instruments are not useful for any tracing in this case since the
application crashes and then is auto-restarted (it's iPad/iPhone app), so all
Intruments history is gone.
I do not see much point instantiating NSMutableURLRequest as autoreleased object
since it needs to be retained for the duration of async call spanning multiple
idle loop cycles. NSURLConnection may retain it internally or not, but keeping
an extra reference for safety should not hurt.
The initialization code boils down to essentially the following:
rq->url_encoded = [url_encode(rq->url) retain];
rq->http_url = [NSURL URLWithString:rq->url_encoded];
rq->http_request = [[NSMutableURLRequest alloc] initWithURL:rq->http_url];
[rq->http_request setHTTPMethod:#"GET"];
NSArray* availableCookies = [rq->service.CookieJar cookiesForURL:rq->http_url];
NSDictionary* headers = [NSHTTPCookie
requestHeaderFieldsWithCookies:availableCookies];
[rq->http_request setAllHTTPHeaderFields:headers];
rq->http_connection = [NSURLConnection alloc];
[rq->http_connection initWithRequest:rq->http_request delegate:rq
startImmediately:YES];
The release procedure is that connectionDidFinishLoading calls [rq->http_connection
cancel] and [rq autorelease], the latter eventually leading to:
// [http_request autorelease];
// delayedAutoRelease(http_request);
[http_connection autorelease];
[http_url autorelease];
[url release];
[url_encoded release];
[response release];
Note that [response release] just pairs previous [response retain] executed inside didReceiveResponse.
If I leave first two lines commented out, NSURLRequest leaks with reference
count 1 per Instruments, and this is the only leak observed.
Whenever I attempt to autorelease http_request whichever way as described above,
a crash occurs.