I'm working with the FMDB, The SQLite Wrapper for iOS.
General Problem:
I'm reading a long string (Base64 encoded image) from the db and then sending it to a UIWebView to be displayed. The when I pop the view controller storing that webview (with the image) the program quits unexpectadly with:
([Controller respondsToSelector:] sent to deallocated instance...btw, I am not calling that method)
The error only cropped up when I started using the large strings.. It never happened before that which leads me to believe it may be something to do with memory and the string not being released in Objective-c after it is sent to the webview.
Possible Solution
I would like to know how I can take control of the string returned from FMDB's "stringForColumn" method. The way I see it is that I can't ever call release on the resultant string as i'm not creating it.
I'm pretty sure I need to dump that string from memory straight after it is sent to the webview (via stringByEvaluatingJavaScriptFromString)
Any ideas greatly appreciated as this is a real show stopper for me :(
Thanks!
if you need for some reason to keep in memory that string, you should call
yourString = [[db stringForColumn:#"foo"]retain];
since then, you are responsible for that string, and you should release when you're done with it.
Related
Long time reader, first time poster here.
I'm creating a test app that creates a NSURLConnection and then displays the result on an UILabel.
I am presently using a Notification Center observer, which fires a notification from within connectionDidFinishLoading to wait for the connection to complete successfully, before I look for the result.
However, what I am struggling to conceptualize is where to store the response data so that I can access it from my View Controller and post the result to the UILabel. (Or from anywhere other than an instance of my Connection Class, for that matter.)
I don't want to post directly to the UILabel from connectionDidFinishLoading. I need a way to decide what I will do with the response later - so my Connection Class stays generalized.
I need a better way to save the response data somewhere, where I can reference it after the instance of the Connection Class has terminated.
Ideally, it should be somewhere that I can have multiple instances of the Connection Class open, and access each response in turn as I need them. This eliminates the potential to just create a variable in my View Controller or somewhere else more global and dump the response to it.
Any ideas on what design patterns could/should be used here would be greatly appreciated!
My suggestions for you to start with are :
Make a singleton class. I will have a property NSDictionary * info or NSArray *infoList; You will have acces to the same data from wherever the app. Update the property, post the notification, access the property from the viewController.
Store the info into a plist/file. Serialize the information, or save plain stream. Whatever you like.Thus after you finish writing to the file, post the notification, read from the file from anyplace within the app.
In both cases if you want multiple connections i suggest going for the factory design Pattern.
I'm trying to use a recent feature of the Scintilla component, which provides OSX-like text-highlighting effect (the yellow animated bouncing box), and I'm stuck with an error that pops up intermittently :
EXC_BAD_ACCESS
pointing to this particular line :
if (layerFindIndicator!=nil)
if ([layerFindIndicator animationForKey:#"animateFound"])
[layerFindIndicator removeAnimationForKey:#"animateFound"];
(the ifs are mine; just in case I caught the object layerFindIndicator being nil, or deallocated or whatever... Unfortunately, it doesn't help...)
layerFindIndicator is seemingly a subclass of CAGradientLayer. (You may see the full code for layerFindIndicator, here).
Since, I'm an absolute newbie to Quartz Core, could please give me any hint as to HOW this could be debugged?
Since, I'm an absolute newbie to Quartz Core, could please give me any hint as to HOW this could be debugged?
This doesn't have anything to do with QuartzCore specifically (at least, I hope not)—it's general this-object-has-been-killed-before-its-time-how-do-I-find-the-killer stuff.
In Xcode:
Edit your current scheme.
For the Profile action, set it to use the Debug build configuration.
Dismiss that and then hit the Profile command.
Xcode will build for that action and then launch Instruments.
Instruments will prompt you to choose a template; you want the Zombies template. Once you've chosen it, Instruments will create a trace document and run your application. Switch to your application (if it isn't already frontmost), then do whatever causes the crash.
If the crash really is a dead-object crash, Zombies will reveal it. You'll get a flag in Instruments's timeline saying something like “message sent to zombie object 0xd3c2b1a0”, and your program will probably exit shortly thereafter.
In that flag is a tiny little button that looks like this: ➲ except it'll be gray. Click on it.
That takes you to the history of that object (actually of that address, including any previous objects or other allocations that have started at that address). Show your Extended Detail Pane (the one that appears on the right showing a stack trace), then scroll down to the end and then move backward (upward) step by step through time, looking at releases and autoreleases, looking for the one that isn't balancing out the object's allocation or a retain.
The solution will probably involve one or more of:
Changing a property to be strong or weak rather than assign/unsafe_unretained
Adding a property where you previously did not strongly own an object
Rearchitecting some things, if it's not clear which of the above you need to do or if either one of them seems like a filthy hack
Switching to ARC to get weak properties and __weak instance variables (both of which get set to nil automatically when the referenced object dies) and to get local variables being implicitly initialized to nil
But it'll depend on what you find in Instruments. And, of course, there's the chance that your problem—the bad access—isn't a dead object at all and all of the above will not help you.
Try this:
if (layerFindIndicator!=nil){
if ([layerFindIndicator animationForKey:#"animateFound"]){
[layerFindIndicator removeAnimationForKey:#"animateFound"];
}
}
Also check to see if it is released else were.
EDIT:
Another thing I found was you didn't have an white space in the if. Your code should now look like this:
if (layerFindIndicator != nil){
if ([layerFindIndicator animationForKey:#"animateFound"]){
[layerFindIndicator removeAnimationForKey:#"animateFound"];
}
}
I have written this trivial action method associated to a textfield.
Every time I enter text into a textfield a search in a PDF is performed and PDFView automatically scroll to selection:
- (IBAction) search:(id)id
{
NSString *query = [self.searchView stringValue]; // get from textfield
selection = [document findString: query fromSelection:NULL withOptions:NSCaseInsensitiveSearch];
if (selection != nil)
{
[self.pdfView setCurrentSelection:selection];
[self.pdfView scrollSelectionToVisible:self.searchView];
}
}
Problem is that after 3 or 4 searches I get EXC_BAD_ACCESS on row (i).
If I debug I see that query contains an NSCFString and not an NSString.
I think it is a memory management problem..but where?
I replicated the same issue inside a trivial testcase:
#interface PDFRef_protoTests : SenTestCase {
#private
PDFDocument *document;
}
........
- (void)setUp
{
[super setUp];
document = [[PDFDocument alloc] initWithURL: #"a local url ..."];
}
- (void)test_exc_bad_access_in_pdfdocument
{
for (int i =0 ;i<100; i++)
{
NSString *temp;
if (i % 2 == 0) temp = #"home";
else if (i % 3 ==0) temp = #"cocoa";
else temp=#"apple";
PDFSelection *selection = [document findString: temp
fromSelection:nil
withOptions:NSCaseInsensitiveSearch];
NSLog(#"Find=%#, iteration=%d", selection, i);
}
}
Update:
1) It seems that it happens also if I use asynchronous search (method beginFindString: withOptions) every time I perform second search.
2) I found a similar problem to mine in MacRuby Issue Tracking: http://www.macruby.org/trac/ticket/1029
3) It seems that if I disable temporarily garbage collection it works but memory goes up.
I wrote something like:
[[NSGarbageCollector defaultCollector] disable];
[[NSGarbageCollector defaultCollector] enable];
surrounding search code
Another Update
Very weird thing is that sometimes all works. Than I clean and Rebuild and problem arises again. From a certain point of view is is not 100% reproducible. I suspect a bug in PDFKit or some compiler setting I have to do
Update Again
Dears it seems very crazy. I'd concentrate on testcase which is very trivial and which replicates easily the problem. What's wrong with it? This testcase works only if I disable (by code or by project setting) GC
Another Update
Boys it seems a bug but I downloaded an example called PDFLinker from Apple website (http://developer.apple.com/library/mac/#samplecode/PDFKitLinker2/Introduction/Intro.html#//apple_ref/doc/uid/DTS10003594). This example implements a PDFViewer. Code of my app and this example are quite similars. For the same search action on same PDF, my memory rises at 300/400 MB while PDFLinker rises at 190MB. Clearly there is something wrong in my code. But I am comparing it bit by bit and I don't think I am inserting memory leaks (and Instrument doesn't give me any evidence). Maybe is there some project-wide setting ?
Update Yet
Changing from 64 bit to 32 bit memory consumption lowered. Surely there is a problem with 64bit and PDFKit. BTW still EXC_BAD_ACCESS on second search
SOLUTION
Crucial point is that PDFKit with Garbage collection is bugged.
If I disable GC all works correctly.
I had another issue that had complicated my analysis: I disabled GC on Project Setting but GC remained enabled on Target Settings. So Apple's example PDFLinked2 worked while mine not.
I agree you have found a bug in PDFKit.
I got various forms of errors (segmentation fault, selector not understood, etc) running your test case. Wrapping the code in #try/#catch doesn't prevent all errors associated with this method.
I also got errors printing the log message.
To work around the bug(s), I suggest you disable GC during your invocation of -findString:fromSelection:, as you've already discovered.
Also, be sure to make copies of the values of interest from selection before re-enabling GC. Don't just copy selection either.
If you conduct searches from multiple places in your code I also suggest you extract a separate method to perform the search. Then you can invoke that one to conduct the searches for you without duplicating the GC disable/enable nesting.
This sort of thing is usually evidence that you're hanging onto a pointer to an object that has been destroyed. Turn on zombie objects (with NSZombieEnabled) to see exactly where and when you're accessing a bad object.
Judging from your screen shot it doesn't seem like you have NSZombie turned on. Probably the reason why it doesn't help you. Here's how you turn it on:
How to enable NSZombie in Xcode?
The screenshot you provided was otherwise very useful, but you really need NSZombie to figure out this kind of errors. Well, unless it's obvious, which it isn't from the code you posted.
EDIT: I read the comment that you're using garbage collection. I'm an iOS developer, so I have very limited experience with garbage collection in Objective-C, but as far as I understand NSZombie doesn't work in a garbage collected environment.
I'm not sure it should be possible to get EXC_BAD_ACCESS in a garbage collected environment, unless you create your own pointer and try to call methods on it without having created an object and I don't see why you would do that.
I've heard that some frameworks doesn't work well with garbage collection, but I wouldn't think PDFKit was among them. Anyway, the solution might be to not use garbage collection. Perhaps you should file a bug report with Apple.
keep PDFSelection *selection as a member variable and pass it in fromSelection: instead of nil.
It is possible that PDFDocument keeps the returned PDFSelection instance to improve the performance.
Did you try retaining the searchview stringvalue object before using it?
As you say it happens when you type fast and it happens for async calls, it is possible that the object stringValue is pointing to is being released between the time your query object is pointing to it, and the time you use it int the search.
You could try something like this to see if the problem persists:
- (IBAction) search:(id)id
{
NSString *query = [[self.searchView stringValue] retain]; // get from textfield
selection = [document findString: query fromSelection:NULL withOptions:NSCaseInsensitiveSearch];
if (selection != nil)
{
[self.pdfView setCurrentSelection:selection];
[self.pdfView scrollSelectionToVisible:self.searchView];
}
[query release];
}
Of course there is also the possibility that document is relased. How do you declare it? is it a property with retain? Can it be released by the time you are searching?
EDIT:
I see that you posted the code with the second parameter as NULL, but in your screenshot, this value is nil.
The documentation says you should use NULL when you want to start the search from the beginning.
http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/QuartzFramework/Classes/PDFDocument_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003873-RH2-DontLinkElementID_1
And as the compiler interprets nil and NULL differently, this could be leading to some weird behavior internally.
Currently I'm writing an app for OSX which will eventually need to be ported to iOS.
The data that needs to be printed is being drawn via CoreGraphics into a PDF context - that is working perfectly.
I've been reading the Apple dev documentation on printing in both iOS and OSX, and, ironically, it actually seems printing from iOS will be easier.
On iOS, UIPrintInteractionController's printingItem property can take an NSData object containing PDF data and print that. Looks like it should be fairly straight-forward.
OSX on the other hand, (looks like it) requires using the NSPrintOperation class - but it seems the only way to get data into an instance is via an NSView. (+printOperationWithView: or +printOperationWithView:printInfo:).
Seeing as the content is formatted and paginated already it seems rather pointless to have to re-draw the PDF data to something like an NSView.
Could there possibly be another way of achieving this that I've missed?
This code is by no means complete, but for anyone who comes across this later, this is basically how you can print directly from an NSData stream:
#define kMimeType #"application/pdf"
#define kPaperType #"A4"
- (void)printData:(NSData *)incomingPrintData {
CFArrayRef printerList; //will soon be an array of PMPrinter objects
PMServerCreatePrinterList(kPMServerLocal, &printerList);
PMPrinter myPrinter;
//iterate over printerList and determine which one you want, assign to myPrinter
PMPrintSession printSession;
PMPrintSettings printSettings;
PMCreateSession(&printSession);
PMCreatePrintSettings(&printSettings);
PMSessionDefaultPrintSettings(printSession, printSettings);
CFArrayRef paperList;
PMPrinterGetPaperList(myPrinter, &paperList);
PMPaper usingPaper;
//iterate over paperList and to set usingPaper to the paper desired
PMPageFormat pageFormat;
PMCreatePageFormatWithPMPaper(&pageFormat, usingPaper);
CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData((CFDataRef)incomingPrintData);
PMPrinterPrintWithProvider(myPrinter, printSettings, pageFormat, (CFStringRef)kMimeType, dataProvider);
}
(via Core Printing Reference)
Beware this code lacks memory management so you will need to use the PMRetain() and PMRelease() functions as well as the CoreFoundation memory-management functions as well.
If anyone can tell me how I can get data from the OSX print dialogue into data I can use in this method I'll accept their answer instead of this. That is, without using Carbon functions.
I have a UITablView with search box, when you type a text, content will show according starting character typed in serach box then when you select uitableview cell, it goes to another page, which has nearly 30 objects like, UILabel and UITextView. This is the way I constructed the page. When I select a company, I get a memory warning: "Did recieve memory warning level 1".
I verified every object, I had given release statement. Still I am getting the problem. How should I avoid the problem?
For starter, launch your application with Instruments using the memory leaks template. This probably can tells you what objects are stay in the memory.
in xcode 5 just go to product -> analyse ... then see the list of the memory leaks break point... just go throw the break point and try to release those are not required variable and class object ....
some bref
Or
This tool tells you what library is leaking, then you can debug your code as you deem suitable. If it is well organized, you will be able to see immediately what object is leaking and fix the problem with ease.