How to use MBProgressHUD with MKNetworkKit? - mbprogresshud

Im using MKNetworkKit with protocols and delegates to send service calls and get json response. Now I want to implement MBProgressHUD to show a busy indicator while the data is being fetched and loaded on the UITable View.
I send the request in viewDidLoad;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[[DataEngine sharedEngine]setFetchUserDataDelegate:self];
[[DataEngine sharedEngine]fetchUserData:#"1"];
}
Where Data Engine is my singleton class where I declared the fetchUserData Method.
I have included the required files i-e; MBProgressHUD.h & MBProgressHUD.m in my project.
Now which code I should write to start and stop the busy indicator and where should I write that code?
Thanks

1) Download project files from Here: https://github.com/jdg/MBProgressHUD
2) Include MBProgressHUD.h & MBProgressHUD.m files into your project directory.
3) Create an instance variable like: MBProgressHUD *progressHUD in your .h file.
4) In .m file, write following code;
progressHUD = [[MBProgressHUD alloc]initWithView:self.view];
[progressHUD show:YES];
[self.view addSubView:progressHUD];
5) To stop the progress indicator write;
[progressHUD hide:YES];

Related

How to download file with form submit using GEB

I'm building up a test in Geb (WebDriver) and need to submit a form which will create a file in response.
I am able to download the file (the Browser save it automatically to the disk), but I wand to check it in GEB.
I've tried withNewWindow(), but it only works on URIs??
I've tried downloadXXX(), but no luck either...
How can I download a file into a variable?
class CSVTest extends GebReportingTest
#Test
void csvCreation() {
to CSVExport
// select entries / fill values
selectAllEntries.value(true)
//// this will do a post
//// the server will render a file and deliver it back as a result of the submit
// CORRECTLY downloads the file
submitButton.click()
// NOT WORKING
withNewWindow (submitButton.click()) {
...
}
// NOT WORKING
def csv = download(submitButton.click())
}
}
You won't be able to intercept the file downloaded by the browser after clicking a button that does a post in any way unfortunately.
You will have to synthesize a post request with the right content which is sent when using the form. While it is possible to do so using Geb's DownloadSupport class it will be complicated and clunky. You're better off using a library for which performing such requests is the main functionality, like for example REST-Assured.

UIDocumentPickerViewController NewBox App Hangs

I am referring WWDC 2014 sample app NewBox for document provider extension.
I am using following code from NeBox app, to import a document from Document Provider to my app.
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url {
BOOL startAccessingWorked = [url startAccessingSecurityScopedResource];
NSURL *ubiquityURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
NSLog(#"ubiquityURL %#",ubiquityURL);
NSLog(#"start %d",startAccessingWorked);
NSFileCoordinator *fileCoordinator = [[NSFileCoordinator alloc] init];
NSError *error;
[fileCoordinator coordinateReadingItemAtURL:url options:0 error:&error byAccessor:^(NSURL *newURL) {
NSData *data = [NSData dataWithContentsOfURL:newURL];
NSLog(#"error %#",error);
NSLog(#"data %#",data);
}];
[url stopAccessingSecurityScopedResource];
}
App totally hangs for coordinateReadingItemAtURL method.
Any inputs will be helpful.
I noticed this problem in NewBox app as well, and decided to trace it. So, there are two extensions in this app: Document Picker and File Provider. To make long story short, there is a race condition between the two when they try to access files within app's document storage folder.
In my opinion, the easiest method to trace down a problem is to put NSLog() in a bunch of locations. The problem is, however, that the debugging output generated by extension won't be visible in Xcode console. The good news is that you can open console in iOS Simulator app by clicking to Debug -> Open System Log menu. This will show all kinds of debugging messages, including those generated by extensions. You can find more about extension debugging here.
By using this method one can easily realize that execution gets stuck in File Provider's startProvidingItemAtURL method. More specifically, the following line causes a deadlock:
[self.fileCoordinator coordinateWritingItemAtURL:url options:0 error:&error byAccessor:^(NSURL *newURL) {
Why is that? Take a look at documentation for coordinateWritingItemAtURL:
If the url parameter specifies a file:
This method waits for other readers and writers of the exact same file to finish in-progress actions.
Function documentPicker that you mentioned calls a read operation, which in its turn triggers a write operation. This is a deadlock. I guess the easiest way to fix it would be to avoid using coordinateWritingItemAtURL in File Provider.
As per documentation:
Each of these methods wait synchronously on the same thread they were invoked on before invoking the passed-in accessor block on the same thread, instead of waiting asynchronously and scheduling invocation of the block on a specific queue.
Apple recommends that you not use file coordination inside this method. The system already guarantees that no other process can access the file while this method is executing. That's the sole reason for this deadlock.
Please refer to this documentation for more details.
You can use block also. Block works too fast, hang problem will get resolve.
Step 1: Take global variable of
UIDocumentPickerViewController *documentPicker;
also decalre
typedef void(^myCompletion)(BOOL);
Step 2: Write a method where allocation takes place and can send callback on completion
-(void) allocateDocumentPicker:(myCompletion) compblock{
//do stuff
documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:#[#"public.content"]
inMode:UIDocumentPickerModeImport];
documentPicker.delegate = self;
documentPicker.modalPresentationStyle = UIModalPresentationFormSheet;
compblock(YES);
}
Step 3: Call the method where allocation is taking place every time you want to open the composer but present it on receiving completion as YES.
-(IBAction)attachmentButtonClicked:(id)sender{
[self allocateDocumentPicker:^(BOOL finished) {
if(finished){
[self.parentScreen presentViewController:documentPicker animated:YES completion:nil];
}
}];
}
Simple Syntax to create own block, take reference from this link
Custom completion block for my own method

Moving playlist to folder doesn't work

I'm having issues moving a newly created SPPlaylist to a (possibly newly created) SPPlaylistFolder.
The idea is to create a folder in the user's Spotify account, where I can add playlists generated from my application. If no such folder has been created, I'm creating a new SPPlaylistFolder and save the folder id for later use.
This is what I'm doing (I've omitted parts of the code that aren't interesting to this subject):
If a folderId has been previously saved (i.e. a folder created), use that ID to load the folder instance:
...
NSError *error = nil;
if (folderId > 0) {
// try to fetch folder
folder = [[SPSession sharedSession] playlistFolderForFolderId:folderId inContainer:container];
}
if (folder == nil) {
// create folder
folder = [container createFolderWithName:#"My Folder" error:&error];
// save a reference to the folder in an instance var
_appFolder = [folder retain];
// (also saving folder.folderId in NSUserDefaults)
}
...
Create an SPPlaylist: [[[SPSession sharedSession] userPlaylists] createPlaylistWithName:#"My Playlist"].
Use KVO to observe the container's playlists property and get notified when the playlist has been created: [[[SPSession sharedSession] userPlaylists] addObserver:self forKeyPath:#"playlists" options:0 context:nil].
Observe the playlists property and move the created playlist to my SPPlaylistFolder (containerPlaylist is the playlist I've identified as the one to move):
...
// identify the index of the containerPlaylist
NSInteger playlistIndex = [[[[SPSession sharedSession] userPlaylists] playlists] indexOfObject:containerPlaylist];
// move playlist
NSError * error = nil;
BOOL success = [container movePlaylistOrFolderAtIndex:playlistIndex ofParent:nil toIndex:0 ofNewParent:_appFolder error:&error];
if (success) {
// This should be a great success. But the playlist hasn't been moved, although the error variable is nil.
}
...
After these steps, both the playlist and folder have been created, but the playlist hasn't been moved. And I'm not getting any errors indicating any invalid input to the movePlaylistOrFolderAtIndex method.
Am I missing something obvious here? Or is the move functionality flawed somehow?
Note: I have also tried to use this code to move playlists that have been created previously (i.e. move all playlists named "My Playlist" to the folder).
EDIT 1: I've investigated this a bit further and actually got some moving action going on. But I had to rewrite some of the code and perform the move several times (or at a later stage). It seems like this is related to the data in SPSession not being entirely synced/up-to-date (?) since it's possible to move playlists when logging later with new session.
Is it possible that it's a syncing issue, i.e. libspotify believes that the SPPlaylistFolder is created and moves SPPlaylists to it, without it actually being created yet?
After having updated my code with reference to this issue on cocoalibspotify, it's working better. What I didn't realize at first was how the syncing with the Spotify service worked. It can easily take several minutes for the changes to be reflected in the Spotify desktop client, for example.

Core Data code and multithreading

The following code is fetch data (fill data for the first time) part of my tableViewController. I am using an NSManagedDocument's managedObjectContext to fill (pre populate) my database. The source is an array that I clean up from my TXT file which rests directly in the Xcode's resources folder. After this creation, I have document cases like closed / open and normal.
The following code inputs and fetches my data onto the table correctly with a fetched results controller request. However, when the data is loading in the thread that is meant to free the UI from this one time data creation (26854 object names) into managedObject.name attribute heavy operation, the tableview and my UI is frozen (for 1-15 seconds that is I think while populating in document.managedObjectContext for the first time for my database).
After 10-15 seconds data is loaded and shows correctly. However, when I stop the simulator and restart the app in simulator, although I save the document as seen in below code, and I use the same fetch results controller setup (and request) the table view shows empty, it is movable in this case (The document state shows open and normal at this stage and file path is same, I checked... It seems like neither autosave nor explicit saveForOverwriting I use work... Or is it something else? I tried a lot of things and I'll go crazy soon. I think it has something to do with my multithreading.
self.managedObjectNames is the array property in the table view and I set it from the TXT file during my table view's loadView:
Is there anybody out there who can show the mistake here? Is it that I give self.managedObjectNames in the method of entity creation category.
Thanks!
- (void)fetchDataIntoDocument:(UIManagedDocument *)document {
dispatch_queue_t fetchQ = dispatch_queue_create("Data fetcher", NULL);
dispatch_async(fetchQ, ^{
[document.managedObjectContext performBlock:^{
for (int i = 0; i < 26854; i++) {
[managedObject managedObjectWithId:[NSNumber numberWithInt:i] andArray:self.managedObjectNames inManagedObjectContext:document.managedObjectContext];
}
// NSLog(#"Save baby!!?");
[document saveToURL:document.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:nil];
}];
});
dispatch_release(fetchQ);
}
The reason why your UI is blocked for 10-15 seconds is because the document.managedObjectContext has been created with NSMainQueueConcurrencyType. That means that the performBlock: method will be executed on the main queue.
Creating the fetchQ in your code does not have any reason. It would have a reason if fetching of data would take some considerable amount of time but adding them would be fast (e.g. creating/modifying only few objects):
dispatch_async(fetchQ, ^{
// fetch data here (e.g. fetchAttribute may take few seconds)
NSString *attribute = fetchAttribute();
[document.managedObjectContext performBlock:^{
MyObject *o;
o = [NSEntityDescription insertNewObjectForEntityForName:#"MyObject"
inManagedObjectContext:document.managedObjectContext];
o.myAttribute = attribute;
}];
});
However I don't know answer to your main question.

iOS - using multiple connections

I've got a simple login view that when you successfully log in, it goes and fetches some json from a server and inserts it into a database. So im using:
// NSURLRequest
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// appending data
}
- (void) connectionDidFinishLoading:(NSURLConnection *)connection
{
// insert into db
}
I want a second connection now to download some documents, how can I utilise the methods above to pass it another URL and handle data in a different manner (not json) for the 2nd NSURLRequest in the same view?
Well, the first thing you need to do is set the delegate of your new NSURLConnection to this class again, so the methods get called (but you knew that). If you're doing these one at a time, store a pointer to the active NSURLRequest, something like:
#property (nonatomic, assign) NSURLRequest *activeURLRequest;
Then check the active request's URL to differentiate the requests:
- (void) connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *urlPath = [[activeURLRequest URL] path];
if([urlPath isEqualToString:#"http://my.url.string/1"])
// insert into DB
else if([urlPath isEqualToString:#"http://my.url.string/2"])
// do the other thing
}
Note you can also compare the NSURL object directly with a stored version of it using isEqual: (or the == operator).
If you're doing more than one at a time, you need another way to differentiate. I recommend using ASIHTTPRequest or AFNetworking to make this easier, but if you want to do it using Apple's libraries then you'll need to spin off multiple threads, keep a record of which thread number is handling which request URL, and use that information in your connectionDidFinishLoading: method.

Resources