My app crashes if I change the control view repeatedly - ios

I have an app that reads from a database some data ( ASIFormDataRequest ) and some images from server files ( setImageWithURL ). My app does it every time the viewController is changed (in order to have everything updated). So I guess there is an issue with cached images If I push my app to the limit switching viewControllers repeatedly my app crashes. Why is this?
All of this has appeared after adding the setImageWithURL functions. Has anyone run into something similar?
I may have to change the way my app works How do you guys do these calls to the server/SQL? How often?
EDITED:(NON_ANSWERED YET ):
XCODE does not say anything about it , when my device crashes it only displays:
2011-12-29 20:14:56.479 CaeDeCajon[4969:6e4f] arrayProductos.id :13
id_producto: 31 2011-12-29 20:14:56.481 CaeDeCajon[4969:7b5f]
arrayProductos.id :25 id_producto: 15 2011-12-29 20:14:56.490
CaeDeCajon[4969:7b5f] arrayProductos.id :31 id_producto: 15
2011-12-29 20:14:56.491 CaeDeCajon[4969:7b5f] arrayProductos.id :32
id_producto: 15 2011-12-29 20:14:56.395 CaeDeCajon[4969:955f]
arrayProductos.id :22 id_producto: 35 (gdb) // HERE IT STOPS
RUNNING.
for a better understanding of the question, my app is designed as follows:
Based on a 5-icon TabBar.
In the second icon I have a tableview with categories of products ( tables, chairs ... ) and if you press on one of them appears another viewController ( the usual detail view ) showing several products in a row ( thanks to a scrollView ) , here there is a navigationController with a button on it, when pressed it takes you to the gallery mode: showing the same products that were shown in the scrollView but in a gallery mode, if you press one of the products it takes you back to the scrollView and move your screen to the product chosen. Pretty normal stuff .
In the third icon I have the check-out basket, where every product picked up on the scrollView (where there is a buy button ) is pressed.
The case is that I "read" Asycn from the database all the information(no pictures) at launchingWithOptions and every time the viewController is changed, to make sure the user does not pick up a product that was sold out. I implanted this on its own and it seemed to worked fine and not to crash my app ( info : name, stock, ... only strings ). light data.
Here is where I think the problem is: I "read" all the images display from a file system in 1&1 ( hosting compony ), and seems to work fine and fast. The problem is when I swap/change the viewController repeatedly and quick between tableView-ScrollView-galleryMode , it crashed 4 times in a row for the same reason. I must say that I get the images for every viewController, for example the images in the scrollView,galleryMode and checkoutView are the same . Can I reuse them ? because I have calls to the URL everyViewController and I guess that is not healthy.
The code to download images:
NSString *URLphotos =[[NSString alloc]initWithFormat:#"http://www.myurl.com/imagenes/%#",picture1.jpg]; // this is not always picture1.jpg but I changed it for making it plainer.
[cell.photo setImageWithURL:[NSURL URLWithString:URLphotos]
placeholderImage:[UIImage imageNamed:#"placeHolder.png"]] ;
Is it enough? I got no more.
wanted tips:
How/where do you guys "read" the images from the URL in order not to crash the app but have the app updated all the time?
Is there something going on with my cache that is making me crazy ? fix it?
Thanks in advance for the interest

It's not clear if you are using Coredata but I had a similar experience with an app. It also had a tab bar and quickly pressing between items would cause random crashes. The issues was coredata being read / updated / deleted at the same time.
I resolved the issue by moving all of my coredata read, writes and updates to the main thread. (example in Swift):
dispatch_async(dispatch_get_main_queue(), {
myDatabase("NameHere", theCommand: "TRUNCATE", theQuery: "dummy")
})
I made a series of functions for the common coredata commands I needed so your code will of course be different. But try running coredata on the main thread and see if your problem is solved.
If you have a CPU intensive coredata task then you will should not run on the main thread but the complexity of the solution is increased (I have only been using Xcode for 3 months) and someone else may be able to help.
But if you are using coredata try this first to see if it solves your problem.

Related

UI not updating (in Swift) during intensive function on main thread

I wondered if anyone could provide advice on how I can ‘force’ the UI to update during a particularly intensive function (on the main thread) in Swift.
To explain: I am trying to add an ‘import’ feature to my app, which would allow a user to import items from a backup file (could be anything from 1 - 1,000,000 records, say, depending on the size of their backup) which get saved to the app’s CodeData database. This function uses a ‘for in’ loop (to cycle through each record in the backup file), and with each ‘for’ in that loop, the function sends a message to a delegate (a ViewController) to update its UIProgressBar with the progress so the user can see the live progress on the screen. I would normally try to send this intensive function to a background thread, and separately update the UI on the main thread… but this isn't an option because creating those items in the CoreData context has to be done on the main thread (according to Swift’s errors/crashes when I initially tried to do it on a background thread), and I think this therefore is causing the UI to ‘freeze’ and not update live on screen.
A simplified version of the code would be:
class CoreDataManager {
var delegate: ProgressProtocol?
// (dummy) backup file array for purpose of this example, which could contain 100,000's of items
let backUp = [BackUpItem]()
// intensive function containing 'for in' loop
func processBackUpAndSaveData() {
let totalItems: Float = Float(backUp.count)
var step: Float = 0
for backUpItem in backUp {
// calculate Progress and tell delegate to update the UIProgressView
step += 1
let calculatedProgress = step / totalItems
delegate?.updateProgressBar(progress: calculatedProgress)
// Create the item in CoreData context (which must be done on main thread)
let savedItem = (context: context)
}
// loop is complete, so save the CoreData context
try! context.save()
}
}
// Meanwhile... in the delegate (ViewController) which updates the UIProgressView
class ViewController: UIViewController, ProgressProtocol {
let progressBar = UIProgressView()
// Delegate function which updates the progress bar
func updateProgressBar(progress: Float) {
// Print statement, which shows up correctly in the console during the intensive task
print("Progress being updated to \(progress)")
// Update to the progressBar is instructed, but isn't reflected on the simulator
progressBar.setProgress(progress, animated: false)
}
}
One important thing to note: the print statement in the above code runs fine / as expected, i.e. throughout the long ‘for in’ loop (which could take a minute or two), the console continuously shows all the print statements (showing the increasing progress values), so I know that the delegate ‘updateProgressBar’ function is definitely firing correctly, but the Progress Bar on the screen itself simply isn’t updating / doesn’t change… and I’m assuming it’s because the UI is frozen and hasn’t got ‘time’ (for want of a better word) to reflect the updated progress given the intensity of the main function running.
I am relatively new to coding, so apologies in advance if I ask for clarification on any responses as much of this is new to me. In case it is relevant, I am using Storyboards (as opposed to SwiftUI).
Just really looking for any advice / tips on whether there are any (relatively easy) routes to resolve this and essentially 'force' the UI to update during this intensive task.
You say "...Just really looking for any advice / tips on whether there are any (relatively easy) routes to resolve this and essentially 'force' the UI to update during this intensive task."
No. If you do time-consuming work synchronously on the main thread, you block the main thread, and UI updates will not take effect until your code returns.
You need to figure out how to run your code on a background thread. I haven't worked with CoreData in quite a while. I know it's possible to do CoreData queries on a background thread, but I no longer remember the details. That's what you're going to need to do.
As to your comment about print statements, that makes sense. The Xcode console is separate from your app's run loop, and is able to display output even if your code doesn't return. The app UI can't do that however.

How to stop execution of for loop in middle in ios

Hi in my application i have two types of syncs. 1.Auto sync 2.Manual Sync. In both the syncs i am downloding a bunch of files from server. If I choose auto sync all files will get download.
Code is like this
for(int i=0;i<filescount;i++)
{
[self downloadfiles];
}
-(void)download files
{
//Here i am creating `NSInvocationOperation`.
if(!synchingfilecount)
totalreceiveddata=0;
}
Based on totalreceiveddata I am updating progress bar. Now the issue is if it autosync it is working fine.While downloading files using autosync and in middle if i click manual sync that time [self downloadfiles]; method will get called but the issue is synchingfilescount is not updating immediately it's completeing the autosyncfiles download and synchingfilescount become 0 due to this reason totalreceiveddata become 0 and progress bar is disappearing. After complete this opertiona again synchingfilecount becomes 4 but i cannot able to see the progress bar due to above situation. Please any one help me how can I come out from this situation.
Ok, if I understand your question correctly, it sounds like you need to create some flags so that you can manage the flow of your code. You can do this by making a boolean property and setting it as you need in the completion block of these sync methods. That way you can call a method or only execute a method after the call is complete.

Call a two digits phone number with Titanium on ios7

I have to call small phone number with only two digits, when I click on a specific view.
This is working well in Android, but this doesn't work on ios6 and 7. By the way, this is working fine with 3 digits.
This is the function I call on click :
$.callView.addEventListener('click', function(e) {
Ti.Platform.openURL('tel:18');
});
This give me that error :
<Warning>: Ignoring unsafe request to open URL tel:18
<Warning>: LaunchServices: application launch failed - received error code 12
I've seen some pieces of answer in this ticket, but it's not related to Titanium.
I've tried to call Ti.Platform.openURL like that :
tel://18?1
tel:18?1
tel:18#1
tel:+18?1
tel:+18#1
But none of theese things works. Have you an idea of what I have to do to make this call ?
Thanks
You can try appending a pause as in tel:18p. This will show up as 18, which you might not like, but this looks like a long standing issue with Apple, so a fix doesn't appear imminent.

Proper way to detect deletion of documents in iCloud across devices?

I can't find an obvious way to detect deletion of a document that I'm monitoring (I cache a list of docs my app cares about).
On Device1:
When I delete a doc, I call
[fileCoordinator coordinateWritingItemAtURL:fileURL options:NSFileCoordinatorWritingForDeleting
error:&err byAccessor:^(NSURL* writingURL) {
[fileManager removeItemAtURL:writingURL error:nil];
This works fine on Device1, everything stays in synch.
On Device2:
I was trying to rely on NSMetadataQuery notifications:
Initial file list is coming in fine on NSMetadataQueryDidFinishGatheringNotification
Document adds/changes are coming in fine via NSMetadataQueryDidUpdateNotification
When i delete a file on Device1, I get a strange result: an update comes in NSMetadataQueryDidUpdateNotification with all my docs (except the one deleted) listed
I'm not sure how I am supposed to detect that the missing file was deleted or that the update notification was for that purpose
Question 1: What should I be checking for?
I tried another route which was to register as a NSFilePresenter for the iCloud URL:
- (NSURL *)iCloudDocumentsURL
{
return [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil] URLByAppendingPathComponent:#"Documents"];
}
I now get called via the NSFilePresenter protocol when files in that URL change, but it's punitively slow to run the logic to determine the missing doc since the callback is vague.
The only call I get back is - (void)presentedItemDidChange;
I was expecting to get a callback via - (void)accommodatePresentedSubitemDeletionAtURL:(NSURL *)url completionHandler:(void (^)(NSError *errorOrNil))completionHandler
But this method is never called.
Question 2: Any idea how to get that working?
Since you're keeping track of files previously reported from iCloud, the deleted file is absent from the current iCloud listing, and so you just compare the two lists to find which was deleted.
That's what I'm doing in my "file manager" view controller, because I keep a NSMutableDictionary of file entries, which includes among other things, keys for the positions of the file "icons" in my master view. When I get notified of an update, and that update results in either more or fewer files, I animate the icon changes based upon those file
changes.
tobinjim is correct in that the NSMetadataQuery returns the entire result set every time. I had expected that only changes to be sent to save bandwidth, but I did not RTFM correctly.
Once I figured that out, I ran into a bug in iOS libraries. This was the crash that was occurring when I deleted a document on one device and the iCloud query update came across to my other device:
2012-06-25 13:15:12.343 app[19779:707] *** -[NSMutableIndexSet indexGreaterThanOrEqualToIndex:]: message sent to deallocated instance 0xdaae2c0
(gdb) bt
#0 0x31937870 in ___forwarding___ ()
#1 0x31892650 in __forwarding_prep_0___ ()
#2 0x373cc676 in __NSIndexSetEnumerate ()
#3 0x373a1ee8 in -[NSIndexSet enumerateIndexesWithOptions:usingBlock:] ()
#4 0x371c1f08 in -[LBQuery _processUpdates] ()
#5 0x373571a6 in -[NSObject(NSThreadPerformAdditions) performSelector:onThread:withObject:waitUntilDone:modes:] ()
#6 0x3737ffa4 in -[NSObject(NSThreadPerformAdditions) performSelector:onThread:withObject:waitUntilDone:] ()
#7 0x371c2274 in -[LBQuery processUpdates] ()
#8 0x373a88d6 in -[NSMetadataQuery _update] ()
I believe I have found the cause of this issue. I was reviewing the new IOS 6 sample code from the presentation by Luke the Hiesterman. I noticed that there were no calls to NSMetadataQuery disable/enableUpdates like there were in the previous iCloud sample apps. I removed all calls to these. I also changed my method which handled NSMetadataQueryDidUpdateNotification calls to run asynchronously but in a queued manner.
There seems to be a race condition occurring between threads for NSMetadataQuery. In some calls the results of the query are fine but at other times, they have been released and the results show up as NSZombie's (thanks to gdb which is way way better than the current lldb). So the enabling and disabling of the query across threads causes the LBQuery to crash by calling objects that have been released.
The removal of all the enabling and disabling for NSMetadataQuery seems to have sped up my app as well, and iCloud seems much more stable.
Since iOS 8 NSMetadataQuery extended NSMetadataQueryDidUpdateNotification userInfo with NSMetadataQueryUpdateRemovedItemsKey which you can use to detect which files were removed.
https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSMetadataQuery_Class/#//apple_ref/doc/constant_group/Keys_for_Use_with_a_Notification_Info_Dictionary

Strange crash when using the new PageCurl effect reading a PDF with MonoTouch and iOS 5.0

I get a strange crash when using the new PageCurl effect reading a PDF with MonoTouch and iOS 5.0.
I've made a simple test case project for MonoDevelop 2.8 and uploaded on GitHub here:
https://github.com/Emasoft/IpaziaPDFReader
It seems that something is getting GCd too early and killing the application, but I can't find what. I've tried to dispose everything in many ways, but in vain. I've already submitted the project tarball to the Xamarin team, but they weren't able to solve the problem.
Is there something broken in the iOS NavigationController memory management? Or am I missing something?
Any help is appreciated, thanks!
UPDATE: I've tried to remove all subviews and sublayers before disposing the objects in all classes, but it still crashing. The only way I found to avoid the crash is to NEVER dispose of the PDF pages, adding them to a List before releasing them, but this is not a viable solution, because in that way memory is consumed rapidly for PDF with many pages and the app crashes anyway when unable to allocate memory for the next page.
Another way to avoid the crashes is to dispose of the PDF pages BEFORE turning the pages, forcing the dispose method on the page controller before creating a new page controller, but in this way the current page will become blank and the transition curls an useless empty page. No solution seems to work.
I've updated project on GitHub with the 3 different solutions I've tried (look in the PageDataSource class), you can uncomment them one at time to see the problems.
//SOLUTION 1
void ForcingPageControllerDispose (BookPageController oldPageController)
{
// --- IF YOU UNCOMMENT THIS, THE CRASHES GO AWAY, BUT THE PAGE IN THE TRANSITION IS BLANK, SO IS NOT VIABLE
currentPageController.View.RemoveFromSuperview ();
currentPageController.Dispose ();
}
//SOLUTION 2
void DisposeThePageControllerWhenDidFinishAnimating (BookPageController oldPageController, UIPageViewController pageViewController)
{
// --- IF YOU UNCOMMENT THIS, THE CRASHES STILL HAPPEN
pageViewController.DidFinishAnimating += delegate(object sender, UIPageViewFinishedAnimationEventArgs e) {
if (currentPageController != null) {
currentPageController.View.RemoveFromSuperview ();
currentPageController.Dispose ();
Console.WriteLine ("currentPageController disposed for page: " + currentPageController.PageIndex);
}
};
}
//SOLUTION 3
void BackupUnusedPagesToAvoidBeingGCd (BookPageController oldPageController)
{
// --- IF YOU UNCOMMENT THIS, THE CRASHES GO AWAY, BUT THE PAGES ARE NOT GARBAGE COLLECTED AND AFTER MANY PAGES IPHONE IS OUT OF MEMORY AND IT CRASHES THE APP
if (parentController.book_page_controllers_reference_list.Contains (currentPageController) == false)
parentController.book_page_controllers_reference_list.Add (currentPageController);
}
I've already submitted the project tarball to the Xamarin team, but they weren't able to solve the problem.
I'm pretty sure the person assigned to your case will come up with the solution. The bigger the test case the more time it can take.
From a quick view the following, in your AppDelegate.cs, is wrong:
PageTurnViewController viewController = new PageTurnViewController ("PageTurnViewController", null);
window.AddSubview (viewController.View);
since the local viewController instance won't have any reference to it once FinishedLaunching returns and the GC will be able to collect it. However it's needed (on the native side) for keep the View fully valid. This can lead to crashes (there could be other cases too, that's the first and only file I checked this morning).
The solution is to promote the viewController to a field. That will make it alive even when the method returns, making it unavailable to collection.
UPDATE
I had a quick look at your code on github.
You are adding (sub)view but you never remove them (when the GC will Dispose them it won't remove them from the super view);
You are losing references to views, e.g. in PageDataSource.cs
newPageController = new BookPageController (nextPageIndex, parentController.currentPDFdocument, parentController);
return newPageController;
After the first page there will already be a reference stored in newPageController which will be overwritten and make the object collectable bug the GC. Since (sub)views are never removed there could still be native reference to them leading to crashes.
For debugging you can add your own finalizers, e.g.
~BookPageController ()
{
Console.WriteLine ("bu-bye");
}
and put breakpoints in them. If they get hit, while you think it's still in use, then you likely found a problem.
Since you are taking a dependency on iOS 5 new features, you should also adopt the new View Controller Containment APIs in iOS 5 that solve a few problems with view controllers.
I suggest you check the WWDC Video and slides for for Session 102 "Implement UIViewController Containment".

Resources