Im pretty new in programming and im currently looking at blocks which im having some issues with. Im having a hard time reaching an object which is defined within my block. Actually I cannot really explain this issue in an accurate way, so ill give you some code and pictures, and hope that it makes sense and that you excuse my dodgy knowledge and try to help me understand the problem.
So Im starting off by running this block
- (void)fetchSite
{
//Initiate the request...
[[FeedStore sharedStore] fetchSites:^(RSSChannel *objSite, NSError *err) {
//When the request completes, this block will be called
if (!err) {
//If everything went ok, grab the object
channelSite = objSite;
//Now we need to extract the first siteId and give it to sharedstore
RSSItem *site = [[channelSite sites] objectAtIndex:0];
NSString *currentSiteId = [NSString stringWithFormat:#"%#", [site siteNumber]];
NSLog(#"DEBUG: LVC: fetchSite: currentSiteId: %#", currentSiteId);
[[FeedStore sharedStore] setCurrentSiteId:currentSiteId];
//Now we can call fetchEntries
[self fetchEntries];
} else {
//If things went bad, show an alart view
UIAlertView *av = [[UIAlertView alloc] initWithTitle:#"Fel" message:#"Kunde inte bedömma din position relaterat till närmaste hållplats, försök gärna igen" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[av show];
//Stop UIRefreshControl
[refreshControl endRefreshing];
}
}];
}
Then fetchEntries is called:
- (void)fetchEntries
{
void (^completionBlock)(RSSChannel *obj, NSError *err) = ^(RSSChannel *obj, NSError *err) {
if (!err) {
//If everything went ok, grab the object, and reload the table and end refreshControl
channel = obj;
//Post notification to refreshTableView method which will reload tableViews data.
[[NSNotificationCenter defaultCenter] postNotificationName:#"RefreshTableView" object:nil];
//Stop UIRefreshControl
[refreshControl endRefreshing];
} else {
//If things went bad, show an alart view
UIAlertView *av = [[UIAlertView alloc] initWithTitle:#"Fel" message:#"Kunde inte hämta avgångar för din hållplats, försök gärna igen" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[av show];
//Stop UIRefreshControl
[refreshControl endRefreshing];
}
};
//Initiate the request...
if (fetchType == ListViewControllerFetchBus) {
[[FeedStore sharedStore] fetchDepartures:completionBlock];
selectedSegment = 0;
} else {
[[FeedStore sharedStore] fetchDeparturesMetro:completionBlock];
selectedSegment = 1;
}
}
Reloading the table:
- (void)refreshTableView:(NSNotification *)notif
{
[[self tableView] reloadData];
}
Heres where I populate my custom table cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Get received data from fetchEntries block
RSSItem *item = [[channel items] objectAtIndex:[indexPath row]];
//Get the new or recycled cell
ItemCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ItemCell"];
//Set the apperance
[[cell lineNumberLabel] setTextColor:[UIColor whiteColor]];
[[cell lineNumberLabel] minimumScaleFactor];
[[cell lineNumberLabel] setFont:[UIFont boldSystemFontOfSize:22]];
[[cell lineNumberLabel] adjustsFontSizeToFitWidth];
[[cell lineNumberLabel] setTextAlignment:NSTextAlignmentCenter];
[[cell destinationLabel] setTextColor:[UIColor whiteColor]];
[[cell displayTimeLabel] setTextColor:[UIColor whiteColor]];
[[cell displayTimeLabel] setTextAlignment:NSTextAlignmentLeft];
//Configure the cell with the item
if ([item lineNumber]) [[cell lineNumberLabel] setText:[item lineNumber]];
if ([item destination]) [[cell destinationLabel] setText:[item destination]];
if ([item displayTime]) [[cell displayTimeLabel] setText:[item displayTime]];
if ([item displayRow1]) [[cell destinationLabel] setText:[item displayRow1]];
return cell;
}
So when im running through these blocks in normal state everything works like a charm.
But the issues starts when Im calling fetchSite method from an UIActionSheet, or actually from an UISegmentedControl which is a subview of UIActionSheet, this takes place here:
- (void)displayPickerView
{
//First im creating an instance to PickerViewController which will handle the UIPickerView which is a subview of UIActionSheet. pickerArrayFromChannel holds entries for UIPickerView to show in its ViewController.
pickerViewController = [[PickerViewController alloc] init];
[pickerViewController initWithItems: pickerArrayFromChannel];
pickerViewController.delegate = self;
//initiate UIActionSheet which needs no delegate or appearance more than its style
actionSheet = [[UIActionSheet alloc] initWithTitle:nil
delegate:nil
cancelButtonTitle:nil
destructiveButtonTitle:nil
otherButtonTitles:nil];
[actionSheet setActionSheetStyle:UIActionSheetStyleBlackTranslucent];
//Create frame and initiate a UIPickerView with this. Set its delegate to the PickerViewController and set it to start at row 0
CGRect pickerFrame = CGRectMake(0, 40, 0, 0);
UIPickerView *pickerView = [[UIPickerView alloc] initWithFrame:pickerFrame];
pickerView.showsSelectionIndicator = YES;
pickerView.delegate = pickerViewController;
pickerView.dataSource = pickerViewController;
[pickerView selectRow:0 inComponent:0 animated:YES];
//Add this pickerView as subview to actionSheet
[actionSheet addSubview:pickerView];
//Now, create two buttons, closeButton and okButton. Which really are UISegmentedControls. Action to closeButton is (for now) dismissActionSheet which holds only following code " [actionSheet dismissWithClickedButtonIndex:0 animated:YES]; " and works fine
UISegmentedControl *closeButton = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObject:#"Stäng"]];
closeButton.momentary = YES;
closeButton.frame = CGRectMake(260, 7.0f, 50.0f, 30.0f);
closeButton.segmentedControlStyle = UISegmentedControlStyleBar;
closeButton.tintColor = [UIColor blackColor];
[closeButton addTarget:self action:#selector(dismissActionSheet) forControlEvents:UIControlEventValueChanged];
[actionSheet addSubview:closeButton];
//OK button
UISegmentedControl *okButton = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObject:#"Visa avgångar"]];
okButton.momentary = YES;
okButton.frame = CGRectMake(10, 7.0f, 100.0f, 30.0f);
okButton.segmentedControlStyle = UISegmentedControlStyleBar;
okButton.tintColor = [UIColor blueColor];
[okButton addTarget:self action:#selector(updateDeparturesFromActionSheet) forControlEvents:UIControlEventValueChanged];
[actionSheet addSubview:okButton];
//Now show actionSheet
[actionSheet showInView:[[UIApplication sharedApplication] keyWindow]];
[actionSheet setBounds:CGRectMake(0, 0, 320, 485)];
}
Now lets look at updateDeparturesFromActionSheet method and we're getting close to where my issues begin (if your still reading, thank you for that
- (void)updateDeparturesFromActionSheet
{
//Dismiss the actionSheet
[actionSheet dismissWithClickedButtonIndex:0 animated:YES];
//Send the selected entry from UIPickerView to currentAddress property in FeedStore, fetchSite method will eventually use this
[[FeedStore sharedStore] setCurrentAddress:[pickerViewController addressFromPickerView]];
//Call fetchSite method
[self fetchSite];
}
fetchSite then eventually calls fetchEntries method, which eventually populate my table. I store received obj (from block) in an property called channel
void (^completionBlock)(RSSChannel *obj, NSError *err) = ^(RSSChannel *obj, NSError *err) {
if (!err) {
//If everything went ok, grab the object, and reload the table and end refreshControl
channel = obj;
The channel object looks like this
channel RSSChannel * 0x07464340
NSObject NSObject
currentString NSMutableString * 0x00000000
lvc ListViewController * 0x08c455d0
items NSMutableArray * 0x08c452d0
sites NSMutableArray * 0x08c452f0
parentParserDelegate id 0x00000000
pickerViewArray NSMutableArray * 0x08c45320
As you can see when I populate my tables cells, I use the info from items inside of the channel object.
Now if your still with me (and havnt fallen asleep) so far I will explain my actual problem, now when you have (hopefully) all the relevant code.
So when I press okButton in my UIActionSheet, updateDeparturesFromActionSheet method gets called. Which calls fetchSite which eventually calls fetchEntries and so far so good, these blocks performs and I get back information. But when I grab fetchEntries obj and put it in channel, it doesnt seems to "update" this object with the new information grabbed by the blocks obj object. Among others it does not seems that channel object gets a new place in the memory (it keeps 0x07464340).
My first thought was to make sure channel object gets released by ARC, by removing all owners of that object, but it seems that even if I do so (and then doublecheck that its null with simple NSLog(#"%#") it keeps getting its old values and memory reference back when I trigger the "update".
After many attempts to release the channel object and doing all sorts of stuff (creating new arrays (outside of block) amongst other things). I keep thinking that some special rule within blocks that I dont understand is messing with me. Any ideas?
Please let me know if anything isnt clear because I've expressed myself bad, its hard to explain an issue that you dont understand yourself. Thanks in advanced.
Related
I'm trying to draw a rect on a UIView when a button is clicked, but for some reason isn't working...
- (IBAction)createNewGame:(id)sender {
[self dismissViewControllerAnimated:NO completion:nil];
//create the new game and add to the array of games, save the index of actual game.
FIALGameModel *newGame = [[FIALGameModel alloc] initWithRows:_row columns:_column];
[_games addObject:(newGame)];
_actualGame = [_games count]-1;
if(_debug==true) {
NSString* messageString = [NSString stringWithFormat: #"Creating a New Game with %d rows and %d columns.", _row, _column];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Alert"
message: messageString
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
UIView *test = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 60, 60)];
test.backgroundColor = [UIColor redColor];
[_areaGame addSubview:test];
}
The alert works fine, but the rect don't.
As #matt hints in comment, the most usual cause of this is that you've not bound your properties or fields to your UI components properly, or else you've tried to run this code before the UIView was loaded. In either case, _areaGame is nil and the addSubview call silently does nothing. Setting a breakpoint on the addSubview line and inspecting _areaGame is the quickest way to verify.
I have used this to implement my custom alert view. To my alert view , I have included a UITextfield to input some details. My problem is how I get the input text from the alert view when the button is pressed.
My implementation is like thisL
- (UIView *)createDemoView
{
UIView *demoView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 290, 100)];
//alertView.tag=2;
UILabel *rateLbl=[[UILabel alloc]initWithFrame:CGRectMake(10, 10, 290, 45)];
rateLbl.backgroundColor=[UIColor clearColor];
rateLbl.font=[UIFont boldSystemFontOfSize:15];
rateLbl.text=#"Rate";
UILabel *cmntLable=[[UILabel alloc]initWithFrame:CGRectMake(10, 45, 290, 45)];
cmntLable.backgroundColor=[UIColor clearColor];
cmntLable.font=[UIFont boldSystemFontOfSize:15];
cmntLable.text=#"Add Comment";
UIImage *dot, *star;
dot = [UIImage imageNamed:#"dot.png"];
star = [UIImage imageNamed:#"star.png"];
JSFavStarControl *rating = [[JSFavStarControl alloc] initWithLocation:CGPointMake(150, 20) dotImage:dot starImage:star];
[rating addTarget:self action:#selector(updateRating:) forControlEvents:UIControlEventValueChanged];
UILabel *lblAlertTItle=[[UILabel alloc]initWithFrame:CGRectMake(5, 5, 290, 45)];
lblAlertTItle.backgroundColor=[UIColor clearColor];
lblAlertTItle.textAlignment=NSTextAlignmentCenter;
lblAlertTItle.font=[UIFont boldSystemFontOfSize:18];
lblAlertTItle.text=#"Choose your sharing option";
UITextField *text = [[UITextField alloc]initWithFrame:CGRectMake(150, 57, 100, 25)];
text.backgroundColor=[UIColor whiteColor];
//[demoView addSubview:lblAlertTItle];
[demoView addSubview:text];
[demoView addSubview:rating];
[demoView addSubview:rateLbl];
[demoView addSubview:cmntLable];
return demoView;
}
-(void)buttonTappedDone:(cellForDatePickCell*)cell{
NSString* appoinmentID =[NSString stringWithFormat:#"%#",cell.appoinment_Dtepick];
NSString* userID = [NSString stringWithFormat:#"%#",cell.USER_Dtepick];
NSDictionary* paras = [[NSDictionary alloc]initWithObjectsAndKeys:appoinmentID,#"appointmentId",userID,#"userId", nil];
jsonpaser* jpser = [[jsonpaser alloc]init];
//[self.indicator_process startAnimating];
[jpser getWebServiceResponce:#"MYYURL" :paras success:^(NSDictionary *responseObject)
{
//requestsF_date = responseObject;
NSLog(#"Appoinment Completed :%#",responseObject);
NSString* selecteDate = [ScheduleView getDate];
NSString* prsonID =[LoginView getPersonID];
NSDictionary* parms = [NSDictionary dictionaryWithObjectsAndKeys:prsonID,#"caregiverPersonId",selecteDate,#"selectedDate", nil];
jsonpaser* jp = [[jsonpaser alloc]init];
[jp getWebServiceResponce:#"MyUrl" :parms success:^(NSDictionary *responseObject)
{
requestsF_date = responseObject;
NSLog(#"Done Clicked :%#",requestsF_date);
[self.tableView reloadData];
}];
}];
// Here we need to pass a full frame
CustomIOS7AlertView *alertView = [[CustomIOS7AlertView alloc] init];
// Add some custom content to the alert view
[alertView setContainerView:[self createDemoView]];
// Modify the parameters
[alertView setButtonTitles:[NSMutableArray arrayWithObjects:#"OK", #"Cancel", nil]];
[alertView setDelegate:self];
// You may use a Block, rather than a delegate.
[alertView setOnButtonTouchUpInside:^(CustomIOS7AlertView *alertView, int buttonIndex) {
//NSLog(#"Block: Button at position %d is clicked on alertView %ld.", buttonIndex, (long)[alertView tag]);
if (buttonIndex==0) {
NSLog(#"button zero [ OK] clicked");
// here i want to get the text box value
}
if (buttonIndex==1) {
NSLog(#"button 1 [ Cancel] clicked");
}
[alertView close];
}];
[alertView setUseMotionEffects:true];
// And launch the dialog
[alertView show];
}
This alert view is popes up when a button clicked in a table view row. can anyone tell me how can i take the textfield value here ?
thank you
The solution to your problem is as simple as a global declaration of the UITextField that you want to access.
Declare the UITextField globally.
Alloc init the text field and add it to the AlertView in your createDemoView method.
In the buttonTappedDone method, check for the text in the UITextField and if not null, you can use it from there.
I have a very simple yet annoying question. I have two view controllers, in the first one i have a button that has to go to a server and do some work, i want to show an alert view containing a spinning indicator, that will show up as soon as the button is pressed and dismissed when the second view controller loads.
I tried this way :
- (IBAction)logMeInFunction:(id)sender {
UIAlertView *waitAlert = [[UIAlertView alloc] initWithTitle:#"Please Wait...." message:nil delegate:self cancelButtonTitle:nil otherButtonTitles: nil];
[waitAlert show];
/* Do Some Api testing and stuff */
[waitAlert dismissWithClickedButtonIndex:0 animated:YES];
[self performSegueWithIdentifier: #"logMe" sender: self];
}
Using this way, the alert show's up and dismisses instantly in the second view controller, not show's up in the first to inform the user that some work is being done and disappears in the second.
Any ideas?
The main problem with your code is that your server call needs to be asynchronous. You are now using dataWithContentsOfURL which is synchronous and which blocks your main thread.
An simple option would be to make that call in a other thread.
UIAlertView *waitAlert = [[UIAlertView alloc] initWithTitle:#"Please Wait...." message:nil delegate:self cancelButtonTitle:nil otherButtonTitles: nil];
[waitAlert show];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSString *strURL2 = [NSString stringWithFormat:#"MyURL"];
NSData *dataURL2 = [NSData dataWithContentsOfURL:[NSURL URLWithString:strURL2]];
NSString *strResult2 = [[NSString alloc] initWithData:dataURL2 encoding:NSUTF8StringEncoding];
NSDictionary *json2 = [strResult2 JSONValue];
NSMutableArray *userExists = [[NSMutableArray alloc] init];
dispatch_async(dispatch_get_main_queue(), ^{
[waitAlert dismissWithClickedButtonIndex:0 animated:YES];
[self performSegueWithIdentifier: #"logMe" sender: self];
});
});
Instead of showing UIAlertview, show the Custome UIView with the label and indicator...
try the below code...
UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(0.0,0.0,200.0,200.0)];
customView.layer.cornerRadius = 5.0;
customView.layer.borderColor = [UIColor lightGrayColor].CGColor;
customView.layer.borderWidth = 1.0;
[self.view addSubview:customView];
UILabel* loadingLabel = [[UILabel alloc] initWithFrame:CGRectMake(leftMargin, topMargin, 200.0, 100.0)];
[loadingLabel setNumberOfLines:4];
[loadingLabel setTextAlignment:NSTextAlignmentCenter];
[loadingLabel setText:#"Loading..."];
[customView addSubview:loadingLabel];
UIActivityIndicatorView* loadingIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(leftMargin + 75.0, topMargin + 45.0, 50.0, 50.0)];
[loadingIndicator setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray];
[customView addSubview:loadingIndicator];
once the server work finished hide/remove the custom view and load your next view controller....
IMO, you need to utilize background thread. The main thread will run a HUD and the background thread will hit server and perform operation.
Psuedo Code:
-(void)sendRequestToServer
{
// TODO: Call server to do some function
// Once you are done with server action, you have to come back to MAIN THREAD
[self performSelectorOnMainThread:#selector(hideHUD) withObject:nil waitUntilDone:NO];
}
- (IBAction)logMeInFunction:(id)sender
{
[MBProgresssHUD showHUDAddedTo:self.view animated:YES];
[self performSelectorInBackground:#selector(sendRequestToServer) withObject:nil];
}
-(void)hideHUD
{
[MBProgressHUD hideHUDForView:self.view animated:YES];
}
NOTE:
Please look at the examples given in the clink and also have a look at dispatch_async and dispatch_sync blocks.
Hope it helps!
To possibilities:
1) UIAlertView or any other view with animation will take some mili second time to present itself on screen. So it might be possible that your service call is quick here and gives you response back before even UIAlertView present on screen.
2) UIAlertView needs a time to display on screen, so might be possible that your server call makes UIAlertview wait until web service execution done as both are performing on main thread. So you should wither use delay to call service function after displaying alert view or you should use GCD.
when I tested my App in instruments for memory leak I found nothing(running using simulator).But When I run it in a mobile and then checked, there are many leaks in UIKit objects. This happening in every view.In simulator no such leaks are showing.
Below is the screenshot of the instrument where some leakage happened.
When I moved to secondViewController from HomeView, no leaks found.If again coming back to home,these many leaks are found. So, is it mean that, I have to release/nil all the UI objects which I used in that secondView. For your information, below are the UI objects I used in secondView.
1.Two Background UIImageView
2.One TitleBar UIImageView
3.3 UIButtons(Back,left and right button for iCarousel)
4.One iCarousel view
5.UIPageController(For this I have used a third Party code SMPageControl)
6.One title label.
Note : Mine is Non-ARC code.
Did anyone faced this problem before.How can I overcome this problem,since I have this problem in every View in my App.Because of this, my App getting memory waring frequently and crashing often.
Thank you.
Below is the my implementation file of that View.
EDIT1 :
#implementation CatalogueViewController
#synthesize deptCarousel = _deptCarousel;
#synthesize carouselItems = _carouselItems;
#synthesize categorymAr = _categorymAr;
#synthesize spacePageControl = _spacePageControl;
#synthesize wrap;
- (void)dealloc {
_deptCarousel = nil;
[_categorymAr release];
_categorymAr = nil;
_deptCarousel.delegate = nil;
_deptCarousel.dataSource = nil;
[_deptCarousel release];
[_carouselItems release];
[viewGesture release];
viewGesture = nil;
[_spacePageControl release];
_spacePageControl = nil;
imgViewBG = nil;
imgViewBG2 = nil;
btnPrev = nil;
btnNext = nil;
// [self releaseObjects];
[super dealloc];
}
- ( IBAction) btnBackClicked {
[self.navigationController popViewControllerAnimated:YES];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = NSLocalizedString(#"catalogue", #"Catalogue");
// Do any additional setup after loading the view from its nib.
_deptCarousel.type = iCarouselTypeLinear;
_deptCarousel.scrollSpeed = 0.3f;
_deptCarousel.bounceDistance = 0.1f;
_deptCarousel.scrollToItemBoundary = YES;
_deptCarousel.stopAtItemBoundary = YES;
[_deptCarousel setScrollEnabled:NO];
UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeNext:)];
swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
[viewGesture addGestureRecognizer:swipeLeft];
[swipeLeft release];
UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipePrev:)];
swipeRight.direction = UISwipeGestureRecognizerDirectionRight;
[viewGesture addGestureRecognizer:swipeRight];
[swipeRight release];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
[viewGesture addGestureRecognizer:singleTap];
[singleTap release];
_carouselItems = [[NSMutableArray alloc] initWithCapacity:1];
_categorymAr = [[NSMutableArray alloc] initWithCapacity:1];
[self addCatalogues];
_spacePageControl.numberOfPages = [_categorymAr count];
[_spacePageControl setPageIndicatorImage:[UIImage imageNamed:IS_IPAD?#"Marker1.fw.png" : #"Markeri.png"]];
[_spacePageControl setCurrentPageIndicatorImage:[UIImage imageNamed:IS_IPAD?#"Marker-Highlight.png" : #"Marker-Highlight_i.png"]];
[_spacePageControl addTarget:self action:#selector(spacePageControl:) forControlEvents:UIControlEventValueChanged];
}
- (void)spacePageControl:(SMPageControl *)sender{
[_deptCarousel scrollToItemAtIndex:sender.currentPage animated:YES];
}
- ( void ) addCatalogues {
[_categorymAr addObjectsFromArray:[[DBModel database] categoryList]];
for (int i = 0; i < [_categorymAr count]; i++) {
[_carouselItems addObject:[NSNumber numberWithInt:i]];
}
[_deptCarousel reloadData];
}
- (void)viewDidUnload{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[self phoneType];
[super viewWillAppear:animated];
if (IS_IPAD) {
UIInterfaceOrientation statusBarOrientation = [[UIApplication sharedApplication] statusBarOrientation];
[self handleOrientation:statusBarOrientation];
}
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- ( void ) phoneType{
if(!IS_IPAD){
if(IS_IPHONE5){
imgViewBG.image = [UIImage imageNamed:#"Background5_5.jpg"];
imgViewBG.center = CGPointMake(162,265);
imgViewBG2.image = [UIImage imageNamed:#"Background11_5.png"];
_spacePageControl.center = CGPointMake(160, 478);
_deptCarousel.center = CGPointMake(160, 355);
viewGesture.center = CGPointMake(160, 355);
btnPrev.center = CGPointMake(25, 355);
btnNext.center = CGPointMake(295, 355);
}
else{
imgViewBG.image = [UIImage imageNamed:#"Background5.jpg"];
imgViewBG2.image = [UIImage imageNamed:#"Background9.png"];
}
}
}
-(void)textFieldDidBeginEditing:(UITextField *)textField{
textFieldSearch.placeholder = #"";
UIButton *clearButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
[clearButton setImage:[UIImage imageNamed:IS_IPAD?#"Btn_X_Large.fw.png":#"Btn_X.fw.png"] forState:UIControlStateNormal];
[clearButton addTarget:self action:#selector(btnClearTextField) forControlEvents:UIControlEventTouchUpInside];
[textFieldSearch setRightViewMode:UITextFieldViewModeAlways];
[textFieldSearch setRightView:clearButton];
[clearButton release];
}
-(void)textFieldDidEndEditing:(UITextField *)textField{
[textFieldSearch setRightView:nil];
if ([textFieldSearch.text isEqualToString:#""]) {
textFieldSearch.placeholder = NSLocalizedString(#"hud_search_for_a_product_here",#"");
}
}
-(IBAction)btnClearTextField{
textFieldSearch.text = #"";
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (IS_IPAD) {
return YES;
} else {
return (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown);
}
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation )toInterfaceOrientation duration:(NSTimeInterval)duration{
if (IS_IPAD) {
[self handleOrientation:toInterfaceOrientation];
}
}
- ( void ) handleOrientation:(UIInterfaceOrientation )toInterfaceOrientation {
if (toInterfaceOrientation == UIInterfaceOrientationPortrait || toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
imgViewBG.image = [UIImage imageNamed:#"Background_Catalogue_P.jpg"];
imgViewBG2.image = [UIImage imageNamed:#"Background_Overlay_P.fw.png"];
btnPrev.center = CGPointMake(90, 640);
btnNext.center = CGPointMake(677, 640);
textFieldSearch.frame = CGRectMake(187, 54, 418, 25);
_deptCarousel.frame = CGRectMake(235, 250, 300, 800);
_spacePageControl.center = CGPointMake(385, 920);
viewGesture.center = CGPointMake(385, 658);
}else {
imgViewBG.image = [UIImage imageNamed:#"Background_Catalogue_L.jpg"];
imgViewBG2.image = [UIImage imageNamed:#"Background_Overlay_L.fw.png"];
btnPrev.center = CGPointMake(54, 385);
btnNext.center = CGPointMake(640, 385);
textFieldSearch.frame = CGRectMake(240, 55, 567, 25);
_deptCarousel.frame = CGRectMake(50, 250, 600, 300);
_spacePageControl.center = CGPointMake(346, 660);
viewGesture.center = CGPointMake(347, 405);
}
}
- ( IBAction )btnDepartmentClicked:(id)sender {
int btnTag = [sender tag];
ProductCategoriesViewController *productView = [[ProductCategoriesViewController alloc] initWithNibName:#"ProductCategoriesView" bundle:nil];
if ( btnTag == 0 ) {
[productView setStrTitle:NSLocalizedString(#"women", #"Women")];
}else if ( btnTag == 1 ) {
[productView setStrTitle:NSLocalizedString(#"men", #"Men")];
} else {
[productView setStrTitle:NSLocalizedString(#"sports", #"Sports")];
}
[self.navigationController pushViewController:productView animated:YES];
[productView release];
}
- ( BOOL ) textFieldShouldReturn:( UITextField * )textField {
[textField resignFirstResponder];
[Flurry logEvent:#"Product searched" withParameters:[NSDictionary dictionaryWithObjectsAndKeys:textField.text,#"1", nil]];
[self productSearch:textField.text isBar:NO isQR:NO];
return YES;
}
- ( void ) productSearch:( NSString * )_searchText isBar:( BOOL )_isBar isQR:( BOOL )_isQr {
if ([_searchText isEqualToString:#""]) {
return;
}
NSMutableArray *ProductList = [[NSMutableArray alloc] init];
[ProductList addObjectsFromArray:[[DBModel database] productSearch:_searchText isBar:_isBar isQR:_isQr]];
if ( [ProductList count] == 0 ) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"product", #"")
message:NSLocalizedString(#"cannot_find_product", #"")
delegate:nil
cancelButtonTitle:NSLocalizedString(#"ok", #"")
otherButtonTitles:nil];
[alert show];
[alert release];
} else {
GeneralProductListViewController *generalProductList = [[GeneralProductListViewController alloc] initWithNibName:IS_IPAD?#"GeneralProductListView~iPad": #"GeneralProductListView" bundle:nil];
[generalProductList setMArProducts:ProductList];
[self.navigationController pushViewController:generalProductList animated:YES];
[generalProductList release];
}
[ProductList release];
}
-(IBAction) spin:(id)sender {
if([sender tag]==0)
{
[_deptCarousel scrollToItemAtIndex:[self.deptCarousel currentItemIndex]+1 animated:YES];
// [_deptCarousel scrollByNumberOfItems:1 duration:2.0];
}
else{
[_deptCarousel scrollToItemAtIndex:[self.deptCarousel currentItemIndex]-1 animated:YES];
}
}
-(void)swipeNext:(UISwipeGestureRecognizer *)recognizer{
[_deptCarousel scrollToItemAtIndex:[self.deptCarousel currentItemIndex]+1 animated:YES];
}
-(void)swipePrev:(UISwipeGestureRecognizer *)recognizer{
[_deptCarousel scrollToItemAtIndex:[self.deptCarousel currentItemIndex]-1 animated:YES];
}
-(void) handleSingleTap:(UITapGestureRecognizer *)recognizer{
if ([_categorymAr count] > 0) {
ProductCategoriesViewController *prodCatView = [[ProductCategoriesViewController alloc] initWithNibName:IS_IPAD ?
#"ProductCategoriesView~iPad" : #"ProductCategoriesView" bundle:nil];
Category *categoryObj = [_categorymAr objectAtIndex:[self.deptCarousel currentItemIndex]];
[prodCatView setStrTitle:categoryObj.categoryName];
[prodCatView setCategoryId:categoryObj.categoryId];
[Flurry logEvent:#"Category List" withParameters:[NSDictionary dictionaryWithObjectsAndKeys:categoryObj.categoryName,[NSString stringWithFormat:#"%d",categoryObj.categoryId], nil]];
[self.navigationController pushViewController:prodCatView animated:YES];
[prodCatView release];
}
}
//-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
// pageControl.currentPage = [self.deptCarousel currentItemIndex] ;
//}
#pragma mark
#pragma mark NavigationBarViewDelegate metho
- ( void ) navigationBackClicked {
[self.navigationController popViewControllerAnimated:YES];
}
#pragma mark -
#pragma mark iCarousel methods
- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel
{
return [_carouselItems count];
}
- (NSUInteger)numberOfVisibleItemsInCarousel:(iCarousel *)carousel
{
//limit the number of items views loaded concurrently (for performance reasons)
return NUMBER_OF_VISIBLE_ITEMS;
}
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index
{
Category *categoryObj = [_categorymAr objectAtIndex:index];
//create a numbered view
UIView *view = nil;
NSString *imagePath = [[APP_CACHES_DIR stringByAppendingPathComponent:#"catalogues"] stringByAppendingString:[NSString stringWithFormat:#"/%d.jpg", categoryObj.categoryId]];
if (![[NSFileManager defaultManager] fileExistsAtPath:imagePath]) {
view = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:IS_IPAD?#"Gallery Placeholder.png":#"Gallery Placeholder.png"]] autorelease];
} else {
view = [[[UIImageView alloc] initWithImage:[UIImage imageWithContentsOfFile:[[APP_CACHES_DIR stringByAppendingPathComponent:#"catalogues"] stringByAppendingString:[NSString stringWithFormat:#"/%d.jpg", categoryObj.categoryId]]]] autorelease];
}
if (IS_IPAD) {
view.frame = CGRectMake(0, 0, 420, 420);
} else {
view.frame = CGRectMake(0, 0, 200, 200);
}
// UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(view.bounds.origin.x, view.bounds.origin.y+view.bounds.size.height, view.bounds.size.width, 44)] autorelease];
// label.text = categoryObj.categoryName;
// label.textColor = [UIColor blackColor];
// label.backgroundColor = [UIColor clearColor];
// label.textAlignment = UITextAlignmentCenter;
// label.font = [UIFont fontWithName:#"Helvetica-Bold" size:IS_IPAD?26:14];
// [view addSubview:label];
return view;
}
- (NSUInteger)numberOfPlaceholdersInCarousel:(iCarousel *)carousel
{
//note: placeholder views are only displayed on some carousels if wrapping is disabled
return INCLUDE_PLACEHOLDERS? 2: 0;
}
- (UIView *)carousel:(iCarousel *)carousel placeholderViewAtIndex:(NSUInteger)index
{
//create a placeholder view
UIView *view = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#""]] autorelease];
UILabel *label = [[[UILabel alloc] initWithFrame:view.bounds] autorelease];
label.text = (index == 0)? #"[": #"]";
label.backgroundColor = [UIColor clearColor];
label.textAlignment = UITextAlignmentCenter;
label.font = [label.font fontWithSize:50];
_spacePageControl.currentPage = index;
// [view addSubview:label];
return view;
}
- (CGFloat)carouselItemWidth:(iCarousel *)carousel
{
//usually this should be slightly wider than the item views
return ITEM_SPACING;
}
- (CATransform3D)carousel:(iCarousel *)_carousel transformForItemView:(UIView *)view withOffset:(CGFloat)offset
{
//implement 'flip3D' style carousel
//set opacity based on distance from camera
view.alpha = 1.0 - fminf(fmaxf(offset, 0.0), 1.0);
//do 3d transform
CATransform3D transform = CATransform3DIdentity;
transform.m34 = _deptCarousel.perspective;
transform = CATransform3DRotate(transform, M_PI / 8.0, 0, 1.0, 0);
return CATransform3DTranslate(transform, 0.0, 0.0, offset * _deptCarousel.itemWidth);
}
- (BOOL)carouselShouldWrap:(iCarousel *)carousel
{
//wrap all carousels
// return NO;
return wrap;
}
- (void)carousel:(iCarousel *)carousel didSelectItemAtIndex:(NSInteger)index {
if (index == [self.deptCarousel currentItemIndex]) {
ProductCategoriesViewController *prodCatView = [[ProductCategoriesViewController alloc] initWithNibName:IS_IPAD ?
#"ProductCategoriesView~iPad" : #"ProductCategoriesView" bundle:nil];
Category *categoryObj = [_categorymAr objectAtIndex:index];
[prodCatView setStrTitle:categoryObj.categoryName];
[prodCatView setCategoryId:categoryObj.categoryId];
[Flurry logEvent:#"Category List" withParameters:[NSDictionary dictionaryWithObjectsAndKeys:categoryObj.categoryName,[NSString stringWithFormat:#"%d",categoryObj.categoryId], nil]];
[self.navigationController pushViewController:prodCatView animated:YES];
[prodCatView release];
}
}
-(void) carouselDidScroll:(iCarousel *)carousel{
// [_deptCarousel scrollToItemAtIndex:[self.deptCarousel currentItemIndex]+3 animated:YES];
// [_deptCarousel scrollByNumberOfItems:1 duration:1];
}
- (void)carouselCurrentItemIndexUpdated:(iCarousel *)carousel{
_spacePageControl.currentPage = [self.deptCarousel currentItemIndex];
}
- ( IBAction ) myCart {
if ( [[DBModel database] isShoppingListEmpty] ) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"at_shopping_cart", #"")
message:NSLocalizedString(#"amsg_shopping_cart_empty", #"")
delegate:nil cancelButtonTitle:NSLocalizedString(#"ok", #"") otherButtonTitles:nil];
[alert show];
[alert release];
return;
}
MyCartViewController *myCartView = [[MyCartViewController alloc] initWithNibName:IS_IPAD ? #"MyCartView~iPad" : #"MyCartView" bundle:nil];
[self.navigationController pushViewController:myCartView animated:YES];
[myCartView release];
}
First, as noted before, use ARC. There is no single thing you could do that will more improve memory management.
Whether you use ARC or not, you should always use accessors to access your ivars (except in init and dealloc). As noted by #LombaX, you're setting your ivars incorrectly in viewDidLoad. Using accessors would help this.
You should run the static analyzer, which will help you find other memory mistakes.
I would suspect that you have an IBOutlet that is configured as retain and that you are not releasing in dealloc. That is the most likely cause of the leaks I'm seeing in your screenshots. ARC will generally make such problems go away automatically.
It is very possible that you have a retain loop. This generally would not show up as a leak. You should use heapshot to investigate that. Your leaks are pretty small; they may not be the actual cause of memory warnings. What you want to investigate (with the Allocations instrument) is what is actually significantly growing your memory use.
But first ARC. Then accessors. Then remove all build warnings. Then remove all Static Analyzer warnings. Then use the Allocations instrument.
Side note: the fact that it says the responsible party is "UIKit" does not mean that this is a bug in UIKit. It just means that UIKit allocated the memory that was later leaked. The cause of the leak could be elsewhere. (That said, UIKit does have several small leaks in it. In general they should not give you trouble, but you may never be able to get rid of 100% of small leaks in an iOS app.)
First:
you have a possible and visible leak, but I'm not sure if it is the same leak you have found in instruments:
These two lines are in your viewDidLoad method
_carouselItems = [[NSMutableArray alloc] initWithCapacity:1];
_categorymAr = [[NSMutableArray alloc] initWithCapacity:1];
But: viewDidLoad: is called every time the view is loaded by it's controller. If the controller purges the view (for example after a memory warning), at the second viewDidLoad your _carouselItems and _categorymAr instance variables will lost the reference to the previously created NSMutableArray, causing a leak
So, change that lines and use the syntesized setters:
self.carouselItems = [[[NSMutableArray alloc] initWithCapacity:1] autorelease];
self.categorymAr = [[[NSMutableArray alloc] initWithCapacity:1] autorelease];
the syntesized setter is configured to release the previous object before assignin a new one.
However: it's possible that you have another leak.
If you can reproduce the leak simply (if I understand, the leak appears simply moving from a VC to another), you can use the "heapshot" function of instruments.
Assuming that your leak appears moving from the first VC to the second and coming back:
open instruments with the allocations tool
go from the first VC to the second and come back.
press "mark heap" on the left. A line will appear.
go again from the first VC to the second and come back.
press "heapshot" again
do this several times (9-10)
the heapshot tool takes a "snapshot" of the living objects at the time you pushed the button and shows you only the difference.
If there are 2-3 new objects, you will see it in the list.
This is a good starting point to investigate a leak.
Look at the attached image:
Consider that you must mark the heap several time and discriminate "false positive" by looking at the object created, in my example you can se a possible leak (heapshot5, 1,66KB), but after looking at the content it's not --> it was a background task that started in that moment.
Moreover, delays of the autorelease pool and the cache of some UIKit objects can show something in the heapshot, this is why I say to try it several times.
One easy way to detect where your leaks come from is to use the Extended Detail view of the Instruments.
To do that click on "View"->"Extended detail" and a right menu with the stack trace of the "leak" will appear. There you will easily find the leaking code for each leak and if they come from your app.
I know lots of people have asked same question, and I've tried lots of them, I don't know what part that I miss, I still can get it to work.
I have a 9*9 table that I want to display and change, because of the size of Iphone Screen, I'm thinking to show one column a time.
What I want is to press the top left button and a UIPickerView will popup allows me to choose which column to display, then reload the UITextFields.
Can anyone give me a detailed answer? I'm still relatively new in this(couple months).
Thank you in advance.
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil
delegate:nil
cancelButtonTitle:nil
destructiveButtonTitle:nil
otherButtonTitles:nil];
[actionSheet setActionSheetStyle:UIActionSheetStyleBlackTranslucent];
CGRect pickerFrame = CGRectMake(0, 40, 0, 0);
UIPickerView *pickerView = [[UIPickerView alloc] initWithFrame:pickerFrame];
pickerView.showsSelectionIndicator = YES;
pickerView.dataSource = self;
pickerView.delegate = self;
[actionSheet addSubview:pickerView];
UISegmentedControl *closeButton = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObject:#"Close"]];
closeButton.momentary = YES;
closeButton.frame = CGRectMake(260, 7.0f, 50.0f, 30.0f);
closeButton.segmentedControlStyle = UISegmentedControlStyleBar;
closeButton.tintColor = [UIColor blackColor];
[closeButton addTarget:self action:#selector(dismissActionSheet:) forControlEvents:UIControlEventValueChanged];
[actionSheet addSubview:closeButton];
[closeButton release];
[actionSheet showInView:[[UIApplication sharedApplication] keyWindow]];
[actionSheet setBounds:CGRectMake(0, 0, 320, 485)];
Above is the code I found, it pops up alright, I have problem adding array to pickerview, and can anyone tell me how should dismissActionSheet method be?
Thank you.
Ok, so I think I understand what you are asking, correct me if this isn't what you need help with...but to add an array (of presumably NSStrings) to the picker view you need to use the - (NSString *)pickerView:titleForRow:forComponent: delegate method. Here is a quick examle:
//Say you have an array of strings you want to present in the pickerview like this
NSArray *arrayOfStrings = [NSArray arrayWithObjects:#"One", #"Two", #"Three", #"Four", nil];
//First we need to say how many rows there will be in the pickerview
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
return [arrayOfStrings count];
}
//Do the same for components (columns) in pickerview
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1;
}
//Here we set the actual title/string on the pickerview
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
if(component==0){
//Grab the nth string from array
return [arrayOfStrings objectAtIndex:row];
}
}
//This is called if a user taps a row
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
if(component==0)
NSLog(#"The User Selected the row titled %#", [arrayOfStrings objectAtIndex:row]);
}
Similairly with actionsheet, you need to add the delegate method for handling when a user clicks a button on the actionsheet
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
if(buttonIndex==0){
NSLog(#"First Button Clicked");
} else if( buttonIndex == 1){
NSLog(#"Second Button Clicked");
}
}