Loading overlay on collection view - ios

I have a loading view that I insert over the top of a view while it is parsing data from the internet using a separate thread, in this case its on top of a UICollectionView.
For some reason that I cannot understand the loading overlay disappears on its own whist the parsing is still taking place, presenting a blank screen for a second or two. It doesn't seem to happen on UITableViews just on UIcollectionviews. Any help would be appreciated.
Activity overlay.m:
#import "ActivityOverlayController.h
#interface ActivityOverlayController ()
#end
#implementation ActivityOverlayController
-(id)initWithFrame:(CGRect)theFrame {
if (self = [super init]) {
frame = theFrame;
self.view.frame = theFrame;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"%#", #"ActivityOverlayController called");
container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 110, 30)];
activityLabel = [[UILabel alloc] init];
activityLabel.text = NSLocalizedString(#"Loading", #"string1");
activityLabel.textColor = [UIColor lightGrayColor];
activityLabel.font = [UIFont boldSystemFontOfSize:17];
[container addSubview:activityLabel];
activityLabel.frame = CGRectMake(0, 3, 70, 25);
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
activityIndicator.color = [UIColor blackColor];
activityIndicator.hidesWhenStopped = TRUE;
[activityIndicator startAnimating];
activityIndicator.frame = CGRectMake(80, 0, 30, 30);
[container addSubview:activityIndicator];
[self.view addSubview:container];
container.center = CGPointMake(frame.size.width/2, frame.size.height/2);
self.view.backgroundColor = [UIColor colorWithRed:255 green:255 blue:255 alpha:0.7];
}
-(void)viewWillAppear:(BOOL) animated {
[super viewWillAppear:animated];
}
-(void)viewWillDisappear:(BOOL) animated {
[super viewWillDisappear:animated];
}
-(void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[activityIndicator stopAnimating];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end
Parsing part of collectionViewController.m:
-(void)ParseCollectionView{
[self performSelectorOnMainThread:#selector(showActivityView) withObject:nil waitUntilDone:YES];
CollectionViewImages = [[NSMutableArray alloc]init];
NSData *xmlData = [[NSData alloc]initWithContentsOfURL:[NSURL URLWithString:GalleryTitle]];
cvTBXML = [[TBXML alloc]initWithXMLData:xmlData];
// Obtain root element
TBXMLElement * root = cvTBXML.rootXMLElement;
TBXMLElement * channel = [TBXML childElementNamed:#"channel" parentElement:root];
if (root)
{
TBXMLElement * item = [TBXML childElementNamed:#"item" parentElement:channel];
while (item !=nil)
{
//create new instance of news object
NSObject *Imagetoparse = [[GalleryImage alloc] init];
TBXMLElement * link = [TBXML childElementNamed:#"link" parentElement:item];
NSString *linktext= [TBXML textForElement:link];
[Imagetoparse setValue:linktext forKey:#"link"];
TBXMLElement * thumbnail = [TBXML childElementNamed:#"description" parentElement:item];
NSString *Thumbnailtext= [TBXML textForElement:thumbnail];
Thumbnailtext = [Thumbnailtext substringFromIndex:21];
NSInteger *slength = Thumbnailtext.length -4;
Thumbnailtext = [Thumbnailtext substringToIndex:slength];
Thumbnailtext = [Thumbnailtext stringByReplacingOccurrencesOfString:#" " withString:#"%20"];
Thumbnailtext = [Thumbnailtext stringByReplacingOccurrencesOfString:#"thumb" withString:#"main"];
NSLog(#"Thumnail1 : %#", Thumbnailtext);
NSData *Thumbnailimage = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: Thumbnailtext]];
[Imagetoparse setValue:Thumbnailimage forKey:#"thumbnail"];
[CollectionViewImages addObject:Imagetoparse];
item = [TBXML nextSiblingNamed:#"item" searchFromElement:item];
}
}
[self.collectionView reloadData];
NSLog(#"%#", #"Finished Parse Collection View");
[self performSelectorOnMainThread:#selector(hideActivityView) withObject:nil waitUntilDone:NO];
}
-(void)showActivityView {
if (overlayController == nil) {
overlayController = [[ActivityOverlayController alloc] initWithFrame:(self.view.superview.bounds)];
}
[self.view.superview insertSubview:overlayController.view aboveSubview:self.view];
}
-(void)hideActivityView {
[overlayController.view removeFromSuperview];
}

Related

How to add textfield in scrollview in ios?

I am making an app in which i am selecting photos from gallery and I want that on every picture or video one textfield will appear so that if i want to describe about that pic or video.
here is the code of display the photos but not showing the textfield on above the every pic in scrollview.
-(void)launchController
{
ELCImagePickerController *elcPicker = [[ELCImagePickerController alloc]initImagePicker];
elcPicker.maximumImagesCount = 100;
elcPicker.returnsOriginalImage = YES;
elcPicker.returnsImage = YES;
elcPicker.onOrder = YES;
elcPicker.mediaTypes = #[(NSString *)kUTTypeImage,(NSString *)kUTTypeMovie];
elcPicker.imagePickerDelegate = self;
[self presentViewController:elcPicker animated:YES completion:Nil];
}
-(void)launchSpecialController
{
ALAssetsLibrary *library = [[ALAssetsLibrary alloc]init];
self.specialLibrary = library;
NSMutableArray *groups = [NSMutableArray array];
[_specialLibrary enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group , BOOL *stop){
if(group){
[groups addObject:group];
}else{
[self displayPickerForGroup:[groups objectAtIndex:0]];
}
} failureBlock:^(NSError *error) {
chosenImages = nil;
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:#"Error" message:[NSString stringWithFormat:#"Album Error: %# - %#", [error localizedDescription], [error localizedRecoverySuggestion]] delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
NSLog(#"A problem occured %#", [error description]);
// an error here mean
}];
}
- (void)displayPickerForGroup:(ALAssetsGroup *)group
{
ELCAssetTablePicker *tablePicker = [[ELCAssetTablePicker alloc] initWithStyle:UITableViewStylePlain];
tablePicker.singleSelection = YES;
tablePicker.immediateReturn = YES;
ELCImagePickerController *elcPicker = [[ELCImagePickerController alloc] initWithRootViewController:tablePicker];
elcPicker.maximumImagesCount = 1;
elcPicker.imagePickerDelegate = self;
elcPicker.returnsOriginalImage = YES; //Only return the fullScreenImage, not the fullResolutionImage
elcPicker.returnsImage = YES; //Return UIimage if YES. If NO, only return asset location information
elcPicker.onOrder = NO; //For single image selection, do not display and return order of selected images
tablePicker.parent = elcPicker;
tablePicker.assetGroup = group;
[tablePicker.assetGroup setAssetsFilter:[ALAssetsFilter allAssets]];
[self presentViewController:elcPicker animated:YES completion:nil];
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
return YES;
}else{
return toInterfaceOrientation != UIInterfaceOrientationPortraitUpsideDown;
}
}
#pragma mark ELCImageControllerDelegate Methods
-(void)elcImagePickerController:(ELCImagePickerController *)picker didFinishPickingMediaWithInfo:(NSArray *)info
{
[self dismissViewControllerAnimated:YES completion:nil];
imageScroll = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 150, self.view.frame.size.width, 450)];
[self.view addSubview:imageScroll];
UITextField *textfield1 = [[UITextField alloc]initWithFrame:CGRectMake(10, 100, 100, 40)];
textfield1.backgroundColor = [UIColor greenColor];
NSMutableArray *textfieldArray = [NSMutableArray arrayWithCapacity:[info count]];
[textfieldArray addObject:textfield1];
textfield1.text= #"hello";
[imageScroll addSubview:textfield1];
for(UIView *v in [imageScroll subviews]){
[v removeFromSuperview];
}
CGRect workingFrame = imageScroll.frame;
workingFrame.origin.x = 0;
NSMutableArray *images = [NSMutableArray arrayWithCapacity:[info count]];
for (NSDictionary *dict in info) {
if ([dict objectForKey:UIImagePickerControllerMediaType] == ALAssetTypePhoto){
if ([dict objectForKey:UIImagePickerControllerOriginalImage]){
UIImage* image=[dict objectForKey:UIImagePickerControllerOriginalImage];
[images addObject:image];
UIImageView *imageview = [[UIImageView alloc] initWithImage:image];
[imageview setContentMode:UIViewContentModeScaleAspectFit];
imageview.frame = workingFrame;
[imageScroll addSubview:imageview];
workingFrame.origin.x = workingFrame.origin.x + workingFrame.size.width;
} else {
NSLog(#"UIImagePickerControllerReferenceURL = %#", dict);
}
} else if ([dict objectForKey:UIImagePickerControllerMediaType] == ALAssetTypeVideo){
if ([dict objectForKey:UIImagePickerControllerOriginalImage]){
UIImage* image=[dict objectForKey:UIImagePickerControllerOriginalImage];
[images addObject:image];
UIImageView *imageview = [[UIImageView alloc] initWithImage:image];
[imageview setContentMode:UIViewContentModeScaleAspectFit];
imageview.frame = workingFrame;
[imageScroll addSubview:imageview];
;
workingFrame.origin.x = workingFrame.origin.x + workingFrame.size.width;
} else {
NSLog(#"UIImagePickerControllerReferenceURL = %#", dict);
}
} else {
NSLog(#"Uknown asset type");
}
}
chosenImages = images;
[imageScroll setPagingEnabled:YES];
[imageScroll setContentSize:CGSizeMake(workingFrame.origin.x, workingFrame.size.height)];
}
- (void)elcImagePickerControllerDidCancel:(ELCImagePickerController *)picker
{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)viewDidLoad {
//chosenImages = [[NSArray alloc]init];
[super viewDidLoad];
[self.view setBackgroundColor:[UIColor whiteColor]];
// textfield1 = [[UITextField alloc]initWithFrame:CGRectMake(10, 100, 100, 40)];
// textfield1.backgroundColor = [UIColor greenColor];
// textfieldArray = [NSMutableArray arrayWithCapacity:[info count]];
// [textfieldArray addObject:textfield1];
// textfield1.text= #"hello";
// [imageScroll addSubview:textfield1];
UIButton *uploadimage = [[UIButton alloc]initWithFrame:CGRectMake(10, 30, 55, 55)];
uploadimage.backgroundColor = [UIColor blueColor];
[uploadimage setTitle:#"multiple images" forState:UIControlStateNormal];
[uploadimage addTarget:self action:#selector(launchSpecialController) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:uploadimage];
UIButton *singleimage = [[UIButton alloc]initWithFrame:CGRectMake(90, 30, 55, 55)];
singleimage.backgroundColor = [UIColor blueColor];
[singleimage setTitle:#"uploadimage" forState:UIControlStateNormal];
[singleimage addTarget:self action:#selector(launchController) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:singleimage];
imagePicker = [[UIImagePickerController alloc]init];
I don't understand your code lines. The problem should be there.
Why are you doing below things?
[imageScroll addSubview:textfield1];
for(UIView *v in [imageScroll subviews]){
[v removeFromSuperview];
}
In first line you are adding textfield to your scrollview and then you are using for loop to remove all subviews. It will remove your textfield from scrollview as well. You should not do this if you want to show textfield to user.
Please try by commenting the for loop. Hope it will work for you.
//Edit begins over here.
I think you should use UICollectionView instead of UIScrollView. In each and every cells of collectionview, you can show image and textfileds. It will be easy for you and also it will look better.
Thanks
Use NSMutableArray store UITextField value in it and call it with image array with function on the same button.
NSMutableArray *arr = [NSMutablearray....];
for (UIView *subV in self.view.subviews){
if([subV isKindOfClass:[UITextField class]])
{
//store it in a NSDictionary, so later can still know which
//textField your text belongs,
NSDictionary *tempDic = [NSDictionary dictionaryWithObjectAndKey:subV.txt
,subV.tag,/*or subVw.placeholder*/,nil];
[arr addObject:tempDic];
}
}

iOS background view not updated using NSTimer while scanning the bluetooth DEVICE

I am trying to work on getting the bluetooth scanning page to pair the BLE device using bluetooth.
I have found the NSUInteger [ _ble.scannedPeripheral count ] do change while scanning. However, when it comes to the execution, the background view images and pages cannot even change. Would you please tell me other wayout make the page change if the variable showing available BLE devices changes from 0 to 1,2 or 3 ?
The below is my code : (Only relevant)
- (void)viewDidAppear:(BOOL)animated
{
if (_ble)
{
_ble.delegate = (id) self;
_ble.btStatus = BT_IDLE;
[_ble startScanning];
}
[NSTimer scheduledTimerWithTimeInterval:0.2f target:self selector:#selector(reloadData) userInfo:nil repeats:YES];
}
-(void) reloadData {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// time consuming workout
dispatch_async(dispatch_get_main_queue(), ^{
// UI update workout for bluetooth scanning
if( [ _ble.scannedPeripheral count ] > 0 ){
[self stopAnimatingImages];
[self setTapDemo : [UIImage imageNamed:#"pairing_d.png"] : #"Pairing" : #"#C4CCCF"] ;
}else{
[self setTapDemo : [self loadingImage] : #"Pairing" : #"#C4CCCF"] ;
[self animateImages];
}
});
});
}
- (void) setTapDemo: (UIImage *) cover : (NSString *) title : (NSString *) colorHex{
image = [UIImage imageNamed:#"shaded_cal.png"];
imageA = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
_container = [[UIView alloc] initWithFrame:[self.view bounds]];
[imageA setImage:cover];
imageA.userInteractionEnabled = YES;
UITapGestureRecognizer *myGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(touchesBegan:)];
myGesture.numberOfTapsRequired = 1;
myGesture.delegate=self;
[imageA addGestureRecognizer:myGesture];
[imageA setContentMode:UIViewContentModeScaleAspectFill];
myLabelQ = [self constructLabelT:title:0.27:0.08: colorHex:25];
myLabelBack =[self constructLabelT:#"BACK":0.04:0.01:#"#C4CCCF":18] ;
if( bleCount > 0){
for(NSUInteger i = 0 ; i < [ _ble.scannedPeripheral count ] ; i ++){
DevicePeriperal *device;
NSString *uuid = [_ble.scannedPeripheralKey objectAtIndex:i];
NSLog (#"device uuid = %#", uuid);
if (uuid)
{
device = [_ble.scannedPeripheral objectForKey:uuid];
NSData * ssx = device.advertdata ;
device.rowIndex = i;
NSLog (#"device advert = %#", ssx);
if([ssx length] > 0){
NSData *macD = [ssx subdataWithRange:NSMakeRange(0, 6)];
NSData *pairD = [ssx subdataWithRange:NSMakeRange(6, 1)];
NSString* newStr = [self hexRepresentationWithSpaces:pairD : NO];
NSString* newMAC = [self hexRepresentationWithSpaces:macD : YES];
NSLog (#"newStr = %#", newStr );
NSLog (#"newMAC = %#", newMAC );
_checkSumByte = [self calculateChecksum:newMAC];
}
NSLog (#"device = %#", device.uuid);
if (device )
{
UIImage *dImage = [UIImage imageNamed:#"device_u.png"];
float change = 0.15*i;
float yPosition = 0.25 + change ;
[imageA addSubview:[self deviceGet:dImage:device.deviceName: 0.40 : yPosition : #"#C4CCCF"]];
}
}
}
//UIImage *dImage = [UIImage imageNamed:#"device_u.png"];
//[imageA addSubview:[self deviceGet:dImage:#"x": 0.40 : 0.25 : #"#C4CCCF"]];
//[imageA addSubview:[self deviceGet:dImage:#"x": 0.40 : 0.40 : #"#C4CCCF"]];
//[imageA addSubview:[self deviceGet:dImage:#"x": 0.40 : 0.55 : #"#C4CCCF"]];
//[imageA addSubview:myLabelS3];
myLabelS1 = [self constructLabelT:#"SPOTTED":0.27:0.723: colorHex:25];
myLabelS2 =[self constructLabelT:#"(choose the one you want to connect)":0.55:0.76:#"#C4CCCF":10] ;
myLabelS3 = [self constructLabelT:#"devices":0.30:0.76: colorHex:25];
}else{
myLabelS1 = [self constructLabelT:#"SCANNING":0.27:0.723: colorHex:25];
myLabelS2 =[self constructLabelT:#"devices":0.51:0.76:#"#C4CCCF":25] ;
myLabelS3 = [self constructLabelT:#"for":0.30:0.76: colorHex:25];
}
[imageA addSubview:myLabelQ];
[imageA addSubview:myLabelBack];
[imageA addSubview:myLabelS1];
[imageA addSubview:myLabelS2];
[imageA addSubview:myLabelS3];
[_container addSubview:imageA];
[self.view addSubview:_container];
[self.view sendSubviewToBack:_container];
}
Each time you call setTapDemo :::, you will create a new _container view and it will be added to self.view . Because you never remove the old one from super view before initialise it again, self.view contains more and more subviews by timer repeats which will finally consume all memory then your app will crash.
Further, [self.view sendSubviewToBack:_container] was called each time while timer was fired, and you never remove your old _container, so any new _container would be hidden behind as result.
In conclusion, I guess you did create updated _container while [ _ble.scannedPeripheral count ] was changed but it was staying behind other subviews. So your may try to modify the code like this:
- (void) setTapDemo: (UIImage *) cover : (NSString *) title : (NSString *) colorHex{
// remove any old _container view
if (_container) [_container removeFromSuperView];
image = [UIImage imageNamed:#"shaded_cal.png"];
imageA = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
_container = [[UIView alloc] initWithFrame:[self.view bounds]];
[imageA setImage:cover];
imageA.userInteractionEnabled = YES;
UITapGestureRecognizer *myGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(touchesBegan:)];
myGesture.numberOfTapsRequired = 1;
myGesture.delegate=self;
[imageA addGestureRecognizer:myGesture];
[imageA setContentMode:UIViewContentModeScaleAspectFill];
myLabelQ = [self constructLabelT:title:0.27:0.08: colorHex:25];
myLabelBack =[self constructLabelT:#"BACK":0.04:0.01:#"#C4CCCF":18] ;
if( bleCount > 0){
for(NSUInteger i = 0 ; i < [ _ble.scannedPeripheral count ] ; i ++){
DevicePeriperal *device;
NSString *uuid = [_ble.scannedPeripheralKey objectAtIndex:i];
NSLog (#"device uuid = %#", uuid);
if (uuid)
{
device = [_ble.scannedPeripheral objectForKey:uuid];
NSData * ssx = device.advertdata ;
device.rowIndex = i;
NSLog (#"device advert = %#", ssx);
if([ssx length] > 0){
NSData *macD = [ssx subdataWithRange:NSMakeRange(0, 6)];
NSData *pairD = [ssx subdataWithRange:NSMakeRange(6, 1)];
NSString* newStr = [self hexRepresentationWithSpaces:pairD : NO];
NSString* newMAC = [self hexRepresentationWithSpaces:macD : YES];
NSLog (#"newStr = %#", newStr );
NSLog (#"newMAC = %#", newMAC );
_checkSumByte = [self calculateChecksum:newMAC];
}
NSLog (#"device = %#", device.uuid);
if (device )
{
UIImage *dImage = [UIImage imageNamed:#"device_u.png"];
float change = 0.15*i;
float yPosition = 0.25 + change ;
[imageA addSubview:[self deviceGet:dImage:device.deviceName: 0.40 : yPosition : #"#C4CCCF"]];
}
}
}
//UIImage *dImage = [UIImage imageNamed:#"device_u.png"];
//[imageA addSubview:[self deviceGet:dImage:#"x": 0.40 : 0.25 : #"#C4CCCF"]];
//[imageA addSubview:[self deviceGet:dImage:#"x": 0.40 : 0.40 : #"#C4CCCF"]];
//[imageA addSubview:[self deviceGet:dImage:#"x": 0.40 : 0.55 : #"#C4CCCF"]];
//[imageA addSubview:myLabelS3];
myLabelS1 = [self constructLabelT:#"SPOTTED":0.27:0.723: colorHex:25];
myLabelS2 =[self constructLabelT:#"(choose the one you want to connect)":0.55:0.76:#"#C4CCCF":10] ;
myLabelS3 = [self constructLabelT:#"devices":0.30:0.76: colorHex:25];
}else{
myLabelS1 = [self constructLabelT:#"SCANNING":0.27:0.723: colorHex:25];
myLabelS2 =[self constructLabelT:#"devices":0.51:0.76:#"#C4CCCF":25] ;
myLabelS3 = [self constructLabelT:#"for":0.30:0.76: colorHex:25];
}
[imageA addSubview:myLabelQ];
[imageA addSubview:myLabelBack];
[imageA addSubview:myLabelS1];
[imageA addSubview:myLabelS2];
[imageA addSubview:myLabelS3];
[_container addSubview:imageA];
//[self.view addSubview:_container];
//[self.view sendSubviewToBack:_container];
// One line of code can do this trick
[self.view insertSubview:_container atIndex:0];
}

iOS - Navigation Title comes from left when back button is pressed

In my app when I visit certain view controllers and touch the Back button in the navigation bar, the navigation title of the resulting viewcontroller looks to be coming from the upper left corner and it looks ugly.
A picture of such an instance is shown below.
I have set the titles programatically.
Can somebody please tell me why this is happening and how I could fix it? Thanks in advance.
Here is my code:
ViewController B
- (void)viewDidLoad
{
[super viewDidLoad];
UILabel * label = [[UILabel alloc] initWithFrame:CGRectMake(0,0,120,45)] ;
label.textColor = COLOR_TEXT_NAVIGATION_BAR_COLOR;
label.backgroundColor = [UIColor clearColor];
label.font = FONT_NAVIGATION_TITLE_BAR;
label.text = [NSString stringWithFormat:PAGE_TITLE_ADD_SERVICE_PROVIDER];
self.navigationItem.titleView = label;
[label sizeToFit];
UIButton *homeButton = [[UIButton alloc] initWithFrame:CGRectMake(20, 20, 20, 20)];
[homeButton setImage:[UIImage imageNamed:IMG_HOME_MENU_BUTTON] forState:UIControlStateNormal];
[homeButton addTarget:self action:#selector(homeMenuAction) forControlEvents:UIControlEventTouchUpInside];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:homeButton];
accNumTextFiled.delegate=self;
nameTextFiled.text = addPayee.providerName;
payLimitTextFiled.text = [NSString stringWithFormat:#"%9.2f", addPayee.paymentLimit];//[NSString stringWithFormat:#"%f",addPayee.paymentLimit];
descTextFiled.text = addPayee.description;
catTextFiled.text = addPayee.maincategory;
subCatTextFiled.text = addPayee.subcategory;
accNumTextFiled.text = addPayee.paymentAccountNumber;
[accNumTextFiled setKeyboardType:UIKeyboardTypeNumberPad];
[self labelCss];
scrollView.contentSize=CGSizeMake(320,450);
}
ViewController A
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = COLOR_BG_INNER_PAGE_COLOR;
NSArray *mappingObjArray1 = #[#"providerName",#"description",#"paymentLimit",#"providerCode",#"maincategory",#"subcategory"];
NSDictionary *queryParams = #{};
commonRestDataMapping = nil;
commonRestDataMapping = [[CommonRestDataMapping alloc] init];
commonRestDataMapping.restDataMappingDelegate = self;
commonRestDataMapping.servicePath = REST_WEB_SERVICE_ADD_PAYEE_LIST;
commonRestDataMapping.mappingObjArray = mappingObjArray1;
commonRestDataMapping.mappingClassString = #"AddPayee";
commonRestDataMapping.mappingKeyPath = #"data";
commonRestDataMapping.mappingQueryParams = queryParams;
[commonRestDataMapping configureRestKit];
[commonRestDataMapping loadDataArray];
if ([self respondsToSelector:#selector(edgesForExtendedLayout)])
self.edgesForExtendedLayout = UIRectEdgeNone;
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[super createNavigationBar:USER_ACCOUNT_PAGE];
[super setNavihationTitle:PAGE_TITLE_ADD_PAYEE];
[self.navigationController setNavigationBarHidden:NO animated:animated];
}
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
//WEB service data initilization
[[WebServiceUrl getSharedInstance] dataiInitialize];
[GMSServices provideAPIKey:#"AIzaSyCBfhnMtcmdhJaaqff72PlvJIjBTZpfSu4"];
NSString* docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString* dbPath = [docPath stringByAppendingPathComponent:#"datadb.sqlite"];
NSFileManager *fm = [NSFileManager defaultManager];
// Check if the database is existed.
if(![fm fileExistsAtPath:dbPath])
{
// If database is not existed, copy from the database template in the bundle
NSString* dbTemplatePath = [[NSBundle mainBundle] pathForResource:#"datadb" ofType:#"sqlite"];
NSError* error = nil;
[fm copyItemAtPath:dbTemplatePath toPath:dbPath error:&error];
if(error){
NSLog(#"can't copy db.");
} else{
NSLog(#" copy db.");
}
} else {
NSLog(#" db exsists");
}
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
UIView *addStatusBar = [[UIView alloc] init];
addStatusBar.frame = CGRectMake(0, 0, 1024, 20);
addStatusBar.backgroundColor = [UIColor blackColor]; //change this to match your navigation bar
[self.window.rootViewController.view addSubview:addStatusBar];
}
homeViewController = [[HomeViewController alloc] initWithNibName:#"HomeViewController" bundle:nil];
UINavigationController *myNav1=[[UINavigationController alloc] initWithRootViewController:homeViewController];
UIImage *navBackgroundImg = [UIImage imageNamed:#"aa1.png"];
[myNav1.navigationBar setBackgroundImage:navBackgroundImg forBarMetrics:UIBarMetricsDefault];//iOS 5 only
// Override point for customization after application launch.
self.viewController = myNav1;
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)transitionToViewController:(UIViewController *)viewController
withTransition:(UIViewAnimationOptions)transition
{
[UIView transitionFromView:self.window.rootViewController.view
toView:viewController.view
duration:0.35f
options:transition
completion:^(BOOL finished){
self.window.rootViewController = viewController;
}];
}

dismissViewControllerAnimated does not deallocate viewcontroller

First off: My project is ARC enabled and I'm using storyboard.
I have a view controller that pushes a segue (modal),
[self performSegueWithIdentifier: #"goInitialSettings" sender: self];
there i'm setting some parameters and store them. When the parameters are stored (true a button tap), the app should return to the original viewcontroller.
This i am doing with this command:
[self.presentingViewController dismissViewControllerAnimated:NO completion:^{}];
I'm noticing that the viewcontroller that i dismiss, never deallocs. How does this come?
I'm adding the code of the 'presented viewcontroller' below:
#interface CenterChoiceController ()
{
UIView* _titleBackground;
UILabel* _lblTitle;
UIButton* _btnGaVerder;
UIPickerView* _myPickerView;
NSArray* _centers;
UILabel* _adresLine;
UILabel* _cityLine;
MKPointAnnotation* _point;
MKMapView* _mapView;
UIActivityIndicatorView* _indicator;
UIAlertView* _alert;
GCenter* _center;
DataManager* _dm;
}
#end
#implementation CenterChoiceController
-(void)dealloc
{
NSLog(#"Centerchoice deallocs");
_titleBackground = nil;
_lblTitle = nil;
_btnGaVerder = nil;
_myPickerView = nil;
_point = nil;
_mapView = nil;
_indicator = nil;
_alert = nil;
_centers = nil;
_adresLine = nil;
_cityLine = nil;
_center = nil;
_dm = nil;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
_dm = [[DataManager alloc]init];
if([_dm hasConnectivity])
{
[_dm fetchCentersForController:self];
}
else
{
[self pushErrorMessage:NSLocalizedString(#"nointernetconnection", nil)];
}
CAGradientLayer *bgLayer = [BackgroundLayer blueGradient];
bgLayer.frame = self.view.bounds;
[self.view.layer insertSublayer:bgLayer atIndex:0];
_titleBackground = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44)];
_titleBackground.backgroundColor = [GColor blueColor];
[self.view addSubview:_titleBackground];
_lblTitle = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width - 10, 44)];
_lblTitle.textAlignment = NSTextAlignmentRight;
_lblTitle.textColor = [GColor whiteColor];
_lblTitle.text = NSLocalizedString(#"bioscoopkeuze", nil);
[self.view addSubview:_lblTitle];
_btnGaVerder = [[UIButton alloc]initWithFrame:CGRectMake(0, self.view.frame.size.height - 54, self.view.frame.size.width, 54)];
[_btnGaVerder setTitle:NSLocalizedString(#"gaverder", nil) forState:UIControlStateNormal];
_btnGaVerder.titleLabel.font = [_btnGaVerder.titleLabel.font fontWithSize:12];
_btnGaVerder.backgroundColor = [GColor blueColor];
[_btnGaVerder setTitleColor:[GColor whiteColor] forState:UIControlStateNormal];
[_btnGaVerder setShowsTouchWhenHighlighted:YES];
[_btnGaVerder addTarget:self action:#selector(gaVerder) forControlEvents:UIControlEventTouchUpInside];
_myPickerView = [[UIPickerView alloc]initWithFrame:CGRectMake(0, 44, self.view.frame.size.width, 200)];
}
-(void)showLoading
{
NSLog(#"shows loading");
_indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
CGPoint cntr = self.view.center;
_indicator.center = cntr;
[_indicator startAnimating];
[self.view addSubview:_indicator];
}
-(void)hideLoading
{
NSLog(#"hides loading");
[_indicator removeFromSuperview];
_indicator = nil;
}
-(void)pushData:(NSArray *)data
{
[self.view addSubview:_btnGaVerder];
[self.view addSubview:_myPickerView];
_centers = data;
_myPickerView.delegate = self;
_myPickerView.dataSource = self;
_dm = [[DataManager alloc]init];
GSettings* settings = [_dm loadSettings];
if(settings == nil)
{
settings = [[GSettings alloc]init];
settings.chosenCenter = [_centers objectAtIndex:0];
settings.loadedCenter = [_centers objectAtIndex:0];
_center = settings.chosenCenter;
settings.notificationsEnabled = YES;
[self changeAddressLines];
}
/*if(settings != nil)
{
GCenter* loaded = settings.loadedCenter;
int i = 0;
BOOL found = NO;
while(i < [_centers count] && !found)
{
GCenter* center = (GCenter*)[_centers objectAtIndex:i];
if(settings.loadedCenter.iD == center.iD)
{
_center = center;
settings.chosenCenter = center;
[_dm storeSettings:settings];
found = YES;
}
i++;
}
//[self.myPickerView selectRow:i-1 inComponent:0 animated:NO];
loaded = nil;
[self changeAddressLines];
}
*/
}
-(void) pushErrorMessage: (NSString*) errorMessage
{
_alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"fout", nil) message:errorMessage delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
_alert.delegate = self;
[_alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex == 0)
{
if(self.navigationController != nil)
{
[self.navigationController popViewControllerAnimated:YES];
}
else
{
//[self initializeData];
}
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)viewWillDisappear:(BOOL)animated
{
[_dm cancelCenterRequest];
/*if(self.tabBarController != nil)
{
dm = [[DataManager alloc]init];
settings = [dm loadSettings];
if([dm hasConnectivity])
{
settings.lastUpdated = nil;
[dm storeSettings:settings];
}
if(settings.loadedCenter.centerCode != settings.chosenCenter.centerCode)
{
UIStoryboard *mystoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
SplashScreenController *controller = [mystoryboard instantiateViewControllerWithIdentifier:#"root"];
[self presentViewController:controller animated:YES completion:nil];
}
dm = nil;
settings = nil;
}
*/
}
-(void)gaVerder
{
_dm = [[DataManager alloc]init];
GSettings* settings = [_dm loadSettings];
if(settings == nil)
{
settings = [[GSettings alloc]init];
settings.notificationsEnabled = YES;
}
if(_center != nil)
{
settings.chosenCenter = _center;
}
[_dm storeSettings:settings];
[_mapView removeFromSuperview];
_mapView = nil;
_titleBackground = nil;
_lblTitle = nil;
_btnGaVerder = nil;
_myPickerView = nil;
_point = nil;
_indicator = nil;
_alert = nil;
_centers = nil;
_adresLine = nil;
_cityLine = nil;
_center = nil;
_dm = nil;
[self.presentingViewController dismissViewControllerAnimated:NO completion:^{}];
//DEZE BLIJFT HELAAS IN HET GEHEUGEN HANGEN... GEEN OPLOSSING GEVONDEN
//[self.navigationController popViewControllerAnimated:NO];
}
//PICKERVIEWDELEGATE EN DATASOURCE
// returns the number of 'columns' to display.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
// returns the # of rows in each component..
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return [_centers count];
}
- (UILabel *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
{
GCenter* center = (GCenter*)[_centers objectAtIndex:row];
NSString* string = center.name;
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, pickerView.frame.size.width, 44)];
label.textColor = [GColor blueColor];
label.font = [label.font fontWithSize:18];
label.text = string;
label.textAlignment = NSTextAlignmentCenter;
return label;
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
_center = (GCenter*)[_centers objectAtIndex:row];
[self changeAddressLines];
}
-(void)changeAddressLines
{
if (_mapView != nil)
{
[_mapView removeAnnotation:_point];
}
[_adresLine removeFromSuperview];
[_cityLine removeFromSuperview];
_adresLine = nil;
_cityLine = nil;
CGRect rctAdres = CGRectMake(0, _myPickerView.frame.origin.y + _myPickerView.frame.size.height -10, self.view.frame.size.width, 20);
_adresLine = [[UILabel alloc]initWithFrame:rctAdres];
_adresLine.textAlignment = NSTextAlignmentCenter;
_adresLine.textColor = [GColor greyColor];
_adresLine.text = _center.street;
CGRect rctCity = CGRectMake(0, rctAdres.origin.y + rctAdres.size.height, self.view.frame.size.width, 20);
_cityLine = [[UILabel alloc]initWithFrame:rctCity];
_cityLine.textAlignment = NSTextAlignmentCenter;
_cityLine.textColor = [GColor greyColor];
_cityLine.font = [_cityLine.font fontWithSize:14];
_cityLine.text = _center.city;
[self.view addSubview:_adresLine];
[self.view addSubview:_cityLine];
if(_mapView == nil)
{
double height;
height = _btnGaVerder.frame.origin.y - _cityLine.frame.origin.y - _cityLine.frame.size.height;
CGRect mapRect = CGRectMake(0, _cityLine.frame.origin.y+3 + _cityLine.frame.size.height, self.view.frame.size.width, height);
_mapView = [[MKMapView alloc]initWithFrame:mapRect];
[self.view addSubview:_mapView];
}
CLLocationCoordinate2D punt;
punt.latitude = _center.latitude;
punt.longitude = _center.longitude;
_point = [[MKPointAnnotation alloc] init];
[_point setCoordinate:punt];
_mapView.centerCoordinate = punt;
_point.title = _center.name;
[_mapView addAnnotation:_point];
[_mapView setCenterCoordinate:punt animated:YES];
MKCoordinateRegion theRegion = _mapView.region;
theRegion.span.longitudeDelta = 0.005;
theRegion.span.latitudeDelta = 0.005;
[_mapView setRegion:theRegion animated:YES];
}
#end
In my case it was a little more complicated. I don't have any variable that has strong reference to my view controller, and my view controller is not a strong delegate to any property/variable contained inside this class itself. After some hard thinking and trials, I found my issue was caused by a NSTimer object defined in the interface. The timer object itself is non-repeatable, but the method invoked by it will schedule the timer again at the end, which as you can imagine would reference this method defined in my view controller again, thus causing circular references. To break out of this loop, I had to invalidate the timer before I dismiss my view controller.
As a summary, these are cases when a view controller can be blocked from deallocating after it is dismissed:
The view controller is being strongly referenced by some outside object;
The view controller is a strong delegate referenced by some object defined within the view controller itself
The dismissViewControllerAnimated:completion: block may reference to self or it has some other code block that may cause a circular references
The view controller has NSTimer objects which can invoke some methods which re-schedules the timer
There could be more, but hopefully we can capture a lot of cases with the above cases.
If your view controller is not deallocated after it is dismissed, there's probably a strong reference to that view controller somewhere in your code. ARC will always deallocate objects that doesn't have strong reference anymore.

Play audio from Parse via UIButton

I've been working on an app that allows audio to be played from Parse (like a social network), but am having trouble getting the code to not have errors.
My .h file
#import <UIKit/UIKit.h>
#interface TalklineViewController : UIViewController
#property (nonatomic, strong) IBOutlet UIScrollView *wallScroll;
#end
My .m file
#interface TalklineViewController ()
#property (nonatomic, retain) NSArray *wallAudioArray;
#end
#implementation TalklineViewController
#synthesize wallAudioArray = _wallAudioArray;
#synthesize wallScroll = _wallScroll;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)getWallAudio
{
//Prepare the query to get all the images in descending order
//1
PFQuery *query = [PFQuery queryWithClassName:#"AudioObject"];
//2
[query orderByDescending:#"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
//3
if (!error) {
//Everything was correct, put the new objects and load the wall
self.wallAudioArray = nil;
self.wallAudioArray = [[NSArray alloc] initWithArray:objects];
[self loadWallViews];
} else {
//4
NSString *errorString = [[error userInfo] objectForKey:#"error"];
UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:#"Error" message:errorString delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[errorAlertView show];
}
}];
}
-(void)loadWallViews
{
//Clean the scroll view
for (id viewToRemove in [self.wallScroll subviews]){
if ([viewToRemove isMemberOfClass:[UIView class]])
[viewToRemove removeFromSuperview];
}
//For every wall element, put a view in the scroll
int originY = 10;
for (PFObject *audioObject in self.wallAudioArray){
//1
//Build the view with the image and the comments
UIView *wallAudioView = [[UIView alloc] initWithFrame:CGRectMake(10, originY, self.view.frame.size.width - 20 , 300)];
//2
//Add the image
PFFile *audio = (PFFile *)[audioObject objectForKey:#"audio"];
UIButton *userAudio = [[UIButton alloc][[UIButton buttonWithType:UIButtonTypeSystem audioWithData:audio.getData]];
userAudio.frame = CGRectMake(0, 0, wallAudioView.frame.size.width, 200);
[wallAudioView addSubview:userAudio];
//3
//Add the info label (User and creation date)
NSDate *creationDate = audioObject.createdAt;
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"HH:mm dd/MM yyyy"];
//4
UILabel *infoLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 210, wallAudioView.frame.size.width,15)];
infoLabel.text = [NSString stringWithFormat:#"Uploaded by: %#, %#", [audioObject objectForKey:#"user"], [df stringFromDate:creationDate]];
infoLabel.font = [UIFont fontWithName:#"Arial-ItalicMT" size:9];
infoLabel.textColor = [UIColor whiteColor];
infoLabel.backgroundColor = [UIColor clearColor];
[wallAudioView addSubview:infoLabel];
//5
//Add the comment
UILabel *commentLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 240, wallAudioView.frame.size.width, 15)];
commentLabel.text = [audioObject objectForKey:#"comment"];
commentLabel.font = [UIFont fontWithName:#"ArialMT" size:13];
commentLabel.textColor = [UIColor whiteColor];
commentLabel.backgroundColor = [UIColor clearColor];
[wallAudioView addSubview:commentLabel];
//6
[self.wallScroll addSubview:wallAudioView];
originY = originY + wallAudioView.frame.size.width + 20;
}
//7
//Set the bounds of the scroll
self.wallScroll.contentSize = CGSizeMake(self.wallScroll.frame.size.width, originY);
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#end
The problem line is:
UIButton *userAudio = [[UIButton alloc][[UIButton buttonWithType:UIButtonTypeSystem audioWithData:audio.getData]];
Any help is greatly appreciated!
UIButton doesn't have an audioWithData method, so that's the biggest issue here; instead, add a target to the button to play the audio with a seperate method:
UIButton *userAudio = [UIButton buttonWithType:UIButtonTypeSystem];
[userAudio setFrame:CGRectMake(20, 20, 100, 44)];
[userAudio setTitle:#"Play Audio!" forState:UIControlStateNormal];
[userAudio addTarget:self action:#selector(playAudio) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:userAudio];
- (void)playAudio
{
// Your audio data and playing code here
// audio.getData
}

Resources