I am using core data to save the text that is added to the labels, each of these labels is on view that can be moved. I am currently saving the text with an entity that is a string, which works fine. How would I use core data to save the CGPoint of the views when moved, to be then loaded back into the saved position when the view is opened again.
The code is as follows.
-CGPoint firstTouchPoint;
//xd = distance between image center and my touch center
float xd;
float yd;
#implementation BlankViewController
-(BOOL)prefersStatusBarHidden
{
return YES;
}
#synthesize name;
-(NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
(IBAction)save:(id)sender {
NSManagedObjectContext *context = [self managedObjectContext];
if (self.name) {
[self.name setValue:self.nameTextField.text forKey:#"name"];
[self.name setValue:self.Label1.text forKey:#"label1"];
[self.name setValue:self.Label2.text forKey:#"label2"];
}
else{
// Create a new managed object
NSManagedObject *newName = [NSEntityDescription insertNewObjectForEntityForName:#"Maths" inManagedObjectContext:context];
[newName setValue:self.nameTextField.text forKey:#"name"];
[newName setValue:self.Label1.text forKey:#"label1"];
[newName setValue:self.Label2.text forKey:#"label2"];
}
- (void)viewDidLoad {
[super viewDidLoad];
if (self.name) {
[self.nameTextField setText:[self.name valueForKey:#"name"]];
[self.Label1 setText:[self.name valueForKey:#"label1"]];
[self.Label2 setText:[self.name valueForKey:#"label2"]]; }}
Code to move the views:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch* bTouch = [touches anyObject];
if ([bTouch.view isEqual:[self imgTest]]) {
firstTouchPoint = [bTouch locationInView:[self view]];
xd = firstTouchPoint.x - [[bTouch view]center].x;
yd = firstTouchPoint.y - [[bTouch view]center].y;
[self.view bringSubviewToFront:self.imgTest];
}
else if ([bTouch.view isEqual:[self imgTest2]]) {
firstTouchPoint = [bTouch locationInView:[self view]];
xd = firstTouchPoint.x - [[bTouch view]center].x;
yd = firstTouchPoint.y - [[bTouch view]center].y;
[self.view bringSubviewToFront:self.imgTest2];
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch* mTouch = [touches anyObject];
if (mTouch.view == [self imgTest]) {
CGPoint cp = [mTouch locationInView:[self view]];
[[mTouch view]setCenter:CGPointMake(cp.x-xd, cp.y-yd)];
}
else if (mTouch.view == [self imgTest2]) {
CGPoint cp = [mTouch locationInView:[self view]];
[[mTouch view]setCenter:CGPointMake(cp.x-xd, cp.y-yd)];
}
}
If you just need to store a single CGPoint with your entity, I would add two required float attributes to your entity (say x and y) and store the point like that.
With the latest Xcode, you can have it generate model objects for you which is easier than dealing with the plain NSManagedObject. With that model object it would also be easy to add a category that defines a point property that you can use to convert the Core Data attributes to a CGPoint and vice versa.
Related
I was able to draw with UIBezierPath in my app. Now I added a UIColor variable so the user, pushing a button, can select a different color. When the user change the color and he start drawing with the new color, all the paths already drawn have the new color.
How can I tell the object to not change the color of the already drawn paths?
Here is my code. Any example of code is much appreciated! :)
(I have my UIColor variable storaged in the appDelegate and I am calling the refresh method from another viewControlle.
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.backgroundColor = [UIColor whiteColor];
myPath = [[UIBezierPath alloc] init];
myPath.lineCapStyle = kCGLineCapRound;
myPath.miterLimit = 0;
myPath.lineWidth = 5;
brushPattern = app.currentColor;
}
return self;
}
-(void)refresh {
AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
brushPattern = app.currentColor;
}
- (void)drawRect:(CGRect)rect {
[brushPattern setStroke];
for (UIBezierPath *_path in pathArray)
[_path strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
myPath = [[UIBezierPath alloc] init];
myPath.lineWidth = 5;
UITouch *mytouch = [[touches allObjects] objectAtIndex:0];
[myPath moveToPoint:[mytouch locationInView:self]];
[pathArray addObject:myPath];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *mytouch = [[touches allObjects] objectAtIndex:0];
[myPath addLineToPoint:[mytouch locationInView:self]];
[self setNeedsDisplay];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
}
I found one demo code for that..
Please check this if it will be helpful to you..
Smooth Line link
I'm getting an exc_bad_access in my app and I can't figure out how to fix it.
I just upgraded to Xcode 4.5 and I'm targeting IOS 5.0. This is also my first time using UIPageViewController. I prefer to use storyboard as much as possible.
What I'm trying to do is recreate a golf course flip book that contains an image on which you can scroll and zoom. I've basically got a mashup now of several tutorials that is mostly working;
1) I have setup a UIPageviewController, which loads a UIScrollview, which adds a imageView to it.
2) flipping by gesture or tap is working, scrolling is working, I have pinch zoom working and a custom single and two finger tapping working for zoom in / out.
3) The crash appears when you start to flip the page with a sliding gesture, but then release your finger. This basically cancels the flip but then a msg gets send to a zombied object.
Here is my 'GuideViewController.h', it acts as the datasource as well as the root.
#import <UIKit/UIKit.h>
#import "YardageHoleViewController.h"
#interface GuideViewController : UIViewController <UIPageViewControllerDataSource>
#property (strong, nonatomic) UIPageViewController *pageController;
#property (strong, nonatomic) NSArray *pageContent;
- (YardageHoleViewController *)viewControllerAtIndex:(NSUInteger)index storyboard (UIStoryboard *)storyboard;
- (NSUInteger)indexOfViewController:(YardageHoleViewController *)viewController;
#end
And here is the Implementation
#import "GuideViewController.h"
#import "GolfCourseAppDelegate.h"
#import "Hole.h"
#interface GuideViewController ()
#end
#implementation GuideViewController
#synthesize pageContent = _pageContent;
#synthesize pageController = _pageController;
- (void)viewWillDisappear:(BOOL)animated
{
[[[GolfCourseAppDelegate sharedDelegate] locationManager] stopUpdatingLocation];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[[[GolfCourseAppDelegate sharedDelegate] locationManager] startUpdatingLocation];
[self createContentPages];
NSDictionary *options =
[NSDictionary dictionaryWithObject:
[NSNumber numberWithInteger:UIPageViewControllerSpineLocationMin]
forKey: UIPageViewControllerOptionSpineLocationKey];
self.pageController = [[UIPageViewController alloc]
initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationVertical options: options];
//self.pageController.delegate = self;
self.pageController.dataSource = self;
[[self.pageController view] setFrame:[[self view] bounds]];
YardageHoleViewController *initialViewController = [self viewControllerAtIndex:0 storyboard:self.storyboard];
NSArray *viewControllers = [NSArray arrayWithObject:initialViewController];
[self.pageController setViewControllers:viewControllers
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:NULL];
[self addChildViewController:self.pageController];
[[self view] addSubview:[self.pageController view]];
[self.pageController didMoveToParentViewController:self];
}
- (YardageHoleViewController *)viewControllerAtIndex:(NSUInteger)index storyboard:(UIStoryboard *)storyboard
{
NSLog(#"getting data view controller at index: %d", index);
// Return the data view controller for the given index.
if (([self.pageContent count] == 0) || (index >= [self.pageContent count])) {
return nil;
}
// Create a new view controller and pass suitable data.
YardageHoleViewController *yardageHoleViewController = [storyboard instantiateViewControllerWithIdentifier:#"YardageHoleViewController"];
yardageHoleViewController.dataObject = [self.pageContent objectAtIndex:index];
return yardageHoleViewController;
}
- (NSUInteger)indexOfViewController:(YardageHoleViewController *)viewController
{
// Return the index of the given data view controller.
// For simplicity, this implementation uses a static array of model objects and the view controller stores the model object; you can therefore use the model object to identify the index.
NSLog(#"returning indexOfViewController : %d", [self.pageContent indexOfObject:viewController.dataObject]);
return [self.pageContent indexOfObject:viewController.dataObject];
}
#pragma mark - Page View Controller Data Source
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
NSLog(#"getting view controller before view controller");
NSUInteger index = [self indexOfViewController:(YardageHoleViewController *)viewController];
if ((index == 0) || (index == NSNotFound)) {
return nil;
}
index--;
return [self viewControllerAtIndex:index storyboard:viewController.storyboard];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSLog(#"getting view controller After view controller");
NSUInteger index = [self indexOfViewController:(YardageHoleViewController *)viewController];
if (index == NSNotFound) {
return nil;
}
index++;
if (index == [self.pageContent count]) {
return nil;
}
return [self viewControllerAtIndex:index storyboard:viewController.storyboard];
}
- (void) createContentPages
{
NSLog(#"creating content Pages");
int totalHoles = [[[GolfCourseAppDelegate appData] objectForKey:#"holes"] count];
NSMutableArray *holeData = [[NSMutableArray alloc] init];
for (int i = 1; i < totalHoles+1; i++)
{
Hole *newHole = [[Hole alloc] initWithHoleNumber:i imageUrl:[NSString stringWithFormat:#"hole%#%d.jpg", (i < 10) ? #"0" : #"", i]];
NSLog(#"Hole image url:%#",newHole.imageUrl);
//int holeNumber = i;
//NSString *imageUrl = [NSString stringWithFormat:#"hole%#%d.jpg", (i < 10) ? #"0" : #"", i];
[holeData addObject:newHole];
}
self.pageContent = [[NSArray alloc] initWithArray:holeData];
NSLog(#"count of holeData %d", self.pageContent.count);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Now for the view we are flipping through 'YardageHoleViewController.h'
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
#import <CoreLocation/CoreLocation.h>
#interface YardageHoleViewController : UIViewController <UIScrollViewDelegate, CLLocationManagerDelegate>
#property (strong, nonatomic) IBOutlet UIScrollView *scrollView;
#property (assign, nonatomic) int hole;
#property (assign, nonatomic) int totalHoles;
#property (strong, nonatomic) id dataObject;
#property (strong, nonatomic) IBOutlet UILabel *frontLabel;
#property (strong, nonatomic) IBOutlet UILabel *middleLabel;
#property (strong, nonatomic) IBOutlet UILabel *backLabel;
- (IBAction)nextPage:(id)sender;
- (IBAction)previousPage:(id)sender;
- (IBAction)infoPage:(id)sender;
- (IBAction)homePage:(id)sender;
- (void)updateDistanceDisplay;
- (NSString *)formatDistance:(NSNumber *)distance;
#end
Here you can see I've got a few things going on. There is some sub views to show distance to cup based on location etc. You also see some outlets, I wanted to have buttons at the top to navigate in addition to the gestures, right now that's not working because the gestures are overriding the button taps (another question for later).
So here is the meat and potatoes 'YardageHoleViewController.m'
#import "YardageHoleViewController.h"
#import "GolfCourseAppDelegate.h"
#import "Hole.h"
#interface YardageHoleViewController ()
#property (nonatomic, strong) UIImageView *imageView;
- (void)centerScrollViewContents;
- (void)scrollViewDoubleTapped:(UITapGestureRecognizer*)recognizer;
- (void)scrollViewTwoFingerTapped:(UITapGestureRecognizer*)recognizer;
#end
#implementation YardageHoleViewController
#synthesize scrollView = _scrollView;
#synthesize hole = _hole;
#synthesize totalHoles = _totalHoles;
#synthesize imageView = _imageView;
#synthesize frontLabel = _frontLabel;
#synthesize middleLabel = _middleLabel;
#synthesize backLabel = _backLabel;
#synthesize dataObject = _dataObject;
/* The point of this method is to get around a slight annoyance with UIScrollView, which is: if the scroll view content size is smaller than its bounds, then it sits at the top-left rather than in the center. This method positions the image view such that it is always in the center of the scroll view’s bounds.
*/
- (void)centerScrollViewContents {
CGSize boundsSize = self.scrollView.bounds.size;
CGRect contentsFrame = self.imageView.frame;
if (contentsFrame.size.width < boundsSize.width) {
contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2.0f;
} else {
contentsFrame.origin.x = 0.0f;
}
if (contentsFrame.size.height < boundsSize.height) {
contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2.0f;
} else {
contentsFrame.origin.y = 0.0f;
}
self.imageView.frame = contentsFrame;
}
- (void)scrollViewDoubleTapped:(UITapGestureRecognizer*)recognizer {
CGPoint pointInView = [recognizer locationInView:self.imageView];
CGFloat newZoomScale = self.scrollView.zoomScale * 1.5f;
newZoomScale = MIN(newZoomScale, self.scrollView.maximumZoomScale);
CGSize scrollViewSize = self.scrollView.bounds.size;
CGFloat w = scrollViewSize.width / newZoomScale;
CGFloat h = scrollViewSize.height / newZoomScale;
CGFloat x = pointInView.x - (w / 2.0f);
CGFloat y = pointInView.y - (h / 2.0f);
CGRect rectToZoomTo = CGRectMake(x, y, w, h);
[self.scrollView zoomToRect:rectToZoomTo animated:YES];
}
- (void)scrollViewTwoFingerTapped:(UITapGestureRecognizer*)recognizer {
// Zoom out slightly, capping at the minimum zoom scale specified by the scroll view
CGFloat newZoomScale = self.scrollView.zoomScale / 1.5f;
newZoomScale = MAX(newZoomScale, self.scrollView.minimumZoomScale);
[self.scrollView setZoomScale:newZoomScale animated:YES];
}
- (UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView {
// Return the view that you want to zoom
return self.imageView;
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
// The scroll view has zoomed, so you need to re-center the contents
[self centerScrollViewContents];
}
- (void)viewDidLoad {
[super viewDidLoad];
Hole *hole = (Hole*)self.dataObject;
self.hole = hole.holeNumber;
UIImage *image = [UIImage imageNamed:hole.imageUrl];
self.imageView = [[UIImageView alloc] initWithImage:image];
self.imageView.frame = (CGRect){.origin=CGPointMake(0.0f, 0.0f), .size=image.size};
[self.scrollView addSubview:self.imageView];
self.scrollView.contentSize = image.size;
//Here you’re setting up two gesture recognizers: one for the double-tap to zoom in, and one for the two-finger-tap to zoom out.
UITapGestureRecognizer *doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(scrollViewDoubleTapped:)];
doubleTapRecognizer.numberOfTapsRequired = 2;
doubleTapRecognizer.numberOfTouchesRequired = 1;
[self.scrollView addGestureRecognizer:doubleTapRecognizer];
UITapGestureRecognizer *twoFingerTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(scrollViewTwoFingerTapped:)];
twoFingerTapRecognizer.numberOfTapsRequired = 1;
twoFingerTapRecognizer.numberOfTouchesRequired = 2;
[self.scrollView addGestureRecognizer:twoFingerTapRecognizer];
[[[GolfCourseAppDelegate sharedDelegate] locationManager] setDelegate:self];
[self updateDistanceDisplay];
self.totalHoles = [[[GolfCourseAppDelegate appData] objectForKey:#"holes"] count];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didRotate:) name:#"UIDeviceOrientationDidChangeNotification" object:nil];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
CGRect scrollViewFrame = self.scrollView.frame;
CGFloat scaleWidth = scrollViewFrame.size.width / self.scrollView.contentSize.width;
self.scrollView.minimumZoomScale = scaleWidth;
self.scrollView.maximumZoomScale = 1.5f;
self.scrollView.zoomScale = scaleWidth;
[self centerScrollViewContents];
}
- (void) didRotate:(NSNotification *)notification {
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight) {
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent];
NSString *moviePath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"hole%#%d", (self.hole < 10) ? #"0" : #"", self.hole] ofType:#"mp4"];
MPMoviePlayerViewController *viewController = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:moviePath]];
viewController.moviePlayer.controlStyle = MPMovieControlStyleNone;
viewController.view.backgroundColor = [UIColor blackColor];
[self presentMoviePlayerViewControllerAnimated:viewController];
} else {
[self dismissMoviePlayerViewControllerAnimated];
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
[self updateDistanceDisplay];
}
- (void) updateDistanceDisplay {
CLLocation *userLocation = [[GolfCourseAppDelegate sharedDelegate] userLocation];
if (userLocation != nil) {
NSMutableDictionary *holeLocations = [[[GolfCourseAppDelegate appData] objectForKey:#"holes"] objectForKey:[NSString stringWithFormat:#"hole%d", self.hole]];
if (round([[[holeLocations objectForKey:#"front"] objectForKey:#"lat"] floatValue]) == 0) {
self.frontLabel.text = #"---";
} else {
CLLocation *frontLocation = [[CLLocation alloc] initWithLatitude:[[[holeLocations objectForKey:#"front"] objectForKey:#"lat"] floatValue] longitude:[[[holeLocations objectForKey:#"front"] objectForKey:#"lng"] floatValue]];
if (([frontLocation distanceFromLocation:userLocation]/1000)>1000){
self.frontLabel.text = #"Out of Range";
}else{
self.frontLabel.text = [self formatDistance:[NSNumber numberWithFloat:([frontLocation distanceFromLocation:userLocation]/1000)]];
}
}
if (round([[[holeLocations objectForKey:#"middle"] objectForKey:#"lat"] floatValue]) == 0) {
self.middleLabel.text = #"---";
} else {
CLLocation *middleLocation = [[CLLocation alloc] initWithLatitude:[[[holeLocations objectForKey:#"middle"] objectForKey:#"lat"] floatValue] longitude:[[[holeLocations objectForKey:#"middle"] objectForKey:#"lng"] floatValue]];
self.middleLabel.text = [self formatDistance:[NSNumber numberWithFloat:([middleLocation distanceFromLocation:userLocation]/1000)]];
}
if (round([[[holeLocations objectForKey:#"back"] objectForKey:#"lat"] floatValue]) == 0) {
self.backLabel.text = #"---";
} else {
CLLocation *backLocation = [[CLLocation alloc] initWithLatitude:[[[holeLocations objectForKey:#"back"] objectForKey:#"lat"] floatValue] longitude:[[[holeLocations objectForKey:#"back"] objectForKey:#"lng"] floatValue]];
self.backLabel.text = [self formatDistance:[NSNumber numberWithFloat:([backLocation distanceFromLocation:userLocation]/1000)]];
}
}
}
- (NSString *) formatDistance:(NSNumber *)distance {
NSNumber *displayDistance;
NSString *unitSuffix = #"";
// Convert km to yards if prefs say so.
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
if ([[preferences stringForKey:#"measurementUnit"] isEqualToString:#"meters"]) {
distance = [NSNumber numberWithFloat:([distance floatValue]*1000.0)];
if ([distance floatValue] < 1000.0) {
displayDistance = distance;
unitSuffix = #"";
} else {
displayDistance = [NSNumber numberWithFloat:([distance floatValue]/1000.0)];
unitSuffix = #"km";
}
} else {
distance = [NSNumber numberWithFloat:([distance floatValue]*1.0936133*1000.0)];
if ([distance floatValue] < 1760.0) {
displayDistance = distance;
unitSuffix = #"";
} else {
displayDistance = [NSNumber numberWithFloat:([distance floatValue]/1760.0)];
unitSuffix = #"mi";
}
}
NSNumberFormatter *decimalStyle = [[NSNumberFormatter alloc] init];
[decimalStyle setFormatterBehavior:NSNumberFormatterBehavior10_4];
[decimalStyle setNumberStyle:NSNumberFormatterDecimalStyle];
[decimalStyle setRoundingMode:NSNumberFormatterRoundFloor];
[decimalStyle setRoundingIncrement:[NSNumber numberWithFloat:1.0]];
NSString *finalDistance = [decimalStyle stringFromNumber:displayDistance];
return [NSString stringWithFormat:#"%#%#", finalDistance, unitSuffix];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
[self setImageView:nil];
[self setScrollView:nil];
[self setFrontLabel:nil];
[self setBackLabel:nil];
[self setBackLabel:nil];
[self setFrontLabel:nil];
[self setMiddleLabel:nil];
[super viewDidUnload];
}
- (IBAction)nextPage:(id)sender {
//TODO
// [((UIPageViewController*)self.parentViewController) setViewControllers:
// target direction:UIPageViewControllerNavigationForward completion:nil];
}
- (IBAction)previousPage:(id)sender {
//TODO
// [((UIPageViewController*)self.parentViewController) setViewControllers:<#(NSArray *)#> direction:UIPageViewControllerNavigationDirectionReverse animated:true completion:nil];
}
- (IBAction)infoPage:(id)sender {
//TODO
}
- (IBAction)homePage:(id)sender {
[self.navigationController popViewControllerAnimated:YES];
}
#end
Whew! lots of reading. So what I tried first was to set the exception break point. No luck. Then I added lots of NSlog statements to see where we crash, and then finally looked for zombies in instruments. Here we see on the malloc "An Objective-C message was sent to a deallocated object (zombie) at address: 0x1386e0e0" in the YardageHoleViewController.
From my NSLog statements I can see that a successful page turn looks like this;
2012-12-16 13:33:52.280 BAP Template[1365:13a03] getting data view controller at index: 0
//started flip right here >
2012-12-16 13:34:06.289 BAP Template[1365:13a03] getting view controller After view controller
2012-12-16 13:34:06.290 BAP Template[1365:13a03] returning indexOfViewController : 0
2012-12-16 13:34:06.292 BAP Template[1365:13a03] getting data view controller at index: 1
and here is what happens when you start to flip then release
2012-12-16 13:36:18.613 BAP Template[1365:13a03] getting data view controller at index: 0
//started flip then released
2012-12-16 13:36:21.828 BAP Template[1365:13a03] getting view controller After view controller
2012-12-16 13:36:21.829 BAP Template[1365:13a03] returning indexOfViewController : 0
2012-12-16 13:36:21.831 BAP Template[1365:13a03] getting data view controller at index: 1
So in some sense it is trying to act like it completed the flip, but we didn't, and then that's when we have a bad time =(
I've set everything to strong, and I really don't know what to try next?
Any suggestions on my code in general would really be appreciated. Thanks in advance!
UPDATE I looked at the crash log in organizer
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 libobjc.A.dylib 0x3737bf78 objc_msgSend + 16
1 CoreLocation 0x3405ddc0 -[CLLocationManager onClientEventLocation:] + 1136
2 CoreLocation 0x3405d77e -[CLLocationManager onClientEvent:supportInfo:] + 194
3 CoreLocation 0x34057e38 __CLClientInvokeCallback_block_invoke_0 + 48
I've since commented out the two lines that start/stop updating location in viewDidLoad / willDisappear in guideViewController.
No more crashing, but why?
Since location updating is started when the view loads, the method
- (void)locationManager:didUpdateToLocation:fromLocation:
gets called continuously in the simulator, like every second, however on the device it only gets called when it detects movement. Inside that method was the call [self updateDistanceDisplay] and that is why it was crashing. The fix I've implemented works well on the device now but it is not bulletproof.
First, in the appDelegate, we want to fix the locationManager.distanceFilter so that not every minor movement triggers the delegate method.
self.locationManager.distanceFilter = 1.0f;
Next, a modification to the didUpdateToLocation method to only update the display if there was a change in the latitude or longitude.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if ((newLocation.coordinate.latitude!=oldLocation.coordinate.latitude)||(newLocation.coordinate.longitude!=oldLocation.coordinate.longitude))
[self updateDistanceDisplay];
}
Again, not bulletproof. There is a case where say user is traveling in a golf cart fast enough and trying to flip pages, we could get into the crash state.
Im having this problem for weeks already. because my app needs a function that will create a UITextfield, undo, and delete the UITexfield. my code create textfield anywhere on the view when you tap it. and it also can undo the last textfield that been created when pressed button undo, it can be move, scale, rotate also, but after i created another new textfield, the old one was been attached to the view. that is why when i long pressed the old textfield, it can be deleted only the new one that was been created can be delete. what will i do how to make that old textfield deleted?here my code.
ViewController.h
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#interface ViewController : UIViewController<UITextFieldDelegate, UIGestureRecognizerDelegate>
{
NSMutableArray *textfieldform;//array for textfield
UITextField *textField1;//a textfield
CGPoint prevPanPoint;// float for moving the textfield anywhere
float prevPinchScale;// float for pinching the textfield
float prevRotation;// float for rotating the textfield
}
#property (nonatomic, retain) NSMutableArray *textfieldform;//array for creating multiple textfield
-(IBAction) undo;
- (IBAction)handleTap2:(UITapGestureRecognizer *)recognizer;
-(IBAction)panGestureAction:(UIPanGestureRecognizer *)pan;
- (IBAction)scaleImage:(UIPinchGestureRecognizer *)recognizer;
- (IBAction)rotateImage:(UIRotationGestureRecognizer *)recognizer;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize textfieldform;
- (void)viewDidLoad{
[super viewDidLoad];
//textfieldform = [[NSMutableArray alloc] init];
// Do any additional setup after loading the view, typically from a nib.
textfieldform = [NSMutableArray arrayWithCapacity:0];//array of the textfield
}
//connected to the self.view
-(IBAction) longPressGesture:(UIGestureRecognizer*)gesture{
[textfieldform removeObject:textField1];
[textField1 removeFromSuperview];
NSLog(#"baaaaaaam!");
}
//make the textfield move to any direction in the self.view
-(IBAction)panGestureAction:(UIPanGestureRecognizer *)pan {
CGPoint translation = [pan translationInView:self.view];
textField1.transform = CGAffineTransformTranslate(textField1.transform, translation.x, translation.y);
[pan setTranslation:CGPointZero inView:self.view];
}
//to make the use of gesture simultaneously within the view
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return YES;
}
//to make the use of gesture simultaneously
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
if([touch.view isKindOfClass:[UIControl class]]) {
return YES;
}
return NO;
}
//to pinch the textfield using 2 fingers.
- (IBAction)scaleImage:(UIPinchGestureRecognizer *)recognizer{
textField1.transform = CGAffineTransformScale(textField1.transform, recognizer.scale, recognizer.scale);
recognizer.scale = 1;
}
//to rotate the textfield using 2 fingers
- (IBAction)rotateImage:(UIRotationGestureRecognizer *)recognizer{
textField1.transform = CGAffineTransformRotate(textField1.transform, recognizer.rotation);
recognizer.rotation = 0;
}
//to remove the last textfield that was been created
-(IBAction)undo{
UITextField *textFieldToRemove = [textfieldform lastObject];
if (textFieldToRemove) {
[textfieldform removeObject:textFieldToRemove];
[textFieldToRemove removeFromSuperview];
}
}
// for the editing of the textfield
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
NSLog(#"textFieldShouldBeginEditing");
return YES;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField{
NSLog(#"textFieldDidBeginEditing");
[textField1 setBackgroundColor:[UIColor colorWithRed:(248/255.0) green:(248/255.0) blue:(255/255.0) alpha:1.0]];
textField1.borderStyle = UITextBorderStyleRoundedRect;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField{
NSLog(#"textFieldShouldEndEditing");
textField.backgroundColor = [UIColor clearColor];
return YES;
}
- (void)textFieldDidEndEditing:(UITextField *)textField{
NSLog(#"textFieldDidEndEditing");
[textField1 setBackgroundColor:[UIColor clearColor]];
textField1.borderStyle = UITextBorderStyleNone;
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
NSLog(#"textField:shouldChangeCharactersInRange:replacementString:");
if ([string isEqualToString:#"#"]) {
return NO;
}
else {
return YES;
}
}
- (BOOL)textFieldShouldClear:(UITextField *)textField{
NSLog(#"textFieldShouldClear:");
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
NSLog(#"textFieldShouldReturn:");
if (textField.tag == textfieldform.count) {
textField1 = (UITextField *)[self.view viewWithTag:textfieldform.count];
[textField1 becomeFirstResponder];
}
else {
[textField resignFirstResponder];
}
return YES;
}
//when tap the user can create a textfield on any direction, it create many different textfield. according to how many tap you do on the view
- (IBAction)handleTap2:(UITapGestureRecognizer *)recognizer{
if (recognizer.state == UIGestureRecognizerStateEnded){
CGPoint point = [recognizer locationInView:[self view]];
textField1 = [[UITextField alloc] init];
textField1.borderStyle = UITextBorderStyleLine;
[textField1 setAdjustsFontSizeToFitWidth:YES];
[textField1 setText:#"TextField"];
CGRect frame ;
frame.origin.x = point.x;
frame.origin.y = point.y;
frame.size.width=200;
frame.size.height=40;
textField1.frame=frame;
textField1.autocorrectionType = UITextAutocorrectionTypeNo;
textField1.keyboardType = UIKeyboardTypeDefault;
textField1.returnKeyType = UIReturnKeyDefault;
textField1.clearButtonMode = UITextFieldViewModeWhileEditing;
textField1.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
textField1.delegate = self;
textField1.tag = textfieldform.count;
[textfieldform addObject:textField1];
[self.view addSubview:textField1];
[textField1 setAdjustsFontSizeToFitWidth:YES];
}
}
- (void)viewDidUnload{
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
You are using wrong method DoAction as selector, instead use LongPressgesture method
Update your code like following:
- (void)viewDidLoad{
[super viewDidLoad];
textfieldform = [[NSMutableArray alloc] init];
textField1 = ... // Initialize textfield
UILongPressGestureRecognizer *holdRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(LongPressgesture:)];
[holdRecognizer setMinimumPressDuration:2];
[holdRecognizer setDelegate:self];
[textField1 addGestureRecognizer:holdRecognizer];
}
- (void)LongPressgesture:(UILongPressGestureRecognizer *)recognizer
{
if (recognizer.state == UIGestureRecognizerStateEnded) {
//[textfieldform removeObject: recognizer.view];
[recognizer.view removeFromSuperview];
NSLog(#"Long press Ended .................");
}
else {
NSLog(#"Long press detected .....................");
}
}
I have a Menu ("myMenu") containing CCMenuItemImages. I would like this menu to detect finger swipes and slide accordingly.
My problem is that the CCMenuItemImages seem to absorb the touch event. The swipe works fine when the user touches the menu outside of the CCMenuItemImages, but not when the touch happens on these.
I have tried to put my menu items in a layer to detect touches (refering to answer Scrollable menu using MenuItem's), but this doesn't seem to work either. Any idea why ?
+(id) scene
{
CCScene *scene = [CCScene node];
ModeMenuScene *layer = [ModeMenuScene node];
[scene addChild: layer];
return scene;
}
-(id) init
{
if( (self=[super init] )) {
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCSprite *background = [CCSprite spriteWithFile:#"bg.png"];
background.position=ccp(winSize.width/2,winSize.height/2);
[self addChild:background];
mode1 = [CCMenuItemImage itemFromNormalImage:#"Mode1.png" selectedImage: #"Mode1.png" target:self selector:#selector(goToMode1:)];
mode1label = [CCLabelTTF labelWithString:[NSString stringWithFormat:#"Level 1 %d", n] dimensions:CGSizeMake(220,53) alignment:UITextAlignmentCenter fontName:#"Arial" fontSize:20.0];
mode1label.color = ccc3(167,0,0);
mode1label.position=ccp(55,-30);
[mode1 addChild:mode1label];
// here same kind of code to define mode2,mode3,mode4 (taken out to reduce size of code)
myMenu=[CCMenu menuWithItems:mode1,mode2,mode3,mode4,nil];
[myMenu alignItemsHorizontallyWithPadding:25];
myMenu.position=ccp(winSize.width/2+40,180);
menuLayer = [CCLayer node];
[menuLayer addChild:myMenu];
[self addChild:menuLayer];
[self enableTouch];
}
return self;
}
-(void) disableTouch{
self.isTouchEnabled=NO;
menuLayer.isTouchEnabled=NO;
}
-(void) enableTouch{
self.isTouchEnabled=YES;
menuLayer.isTouchEnabled=YES;
}
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:[touch view]];
if(location.y>100 && location.y<260) {
draggingMenu=1;
x_initial = location.x;
}
else draggingMenu=0;
}
-(void) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:[touch view]];
if(draggingMenu==1) {
CGSize winSize = [[CCDirector sharedDirector] winSize];
int x = myMenu.position.x+location.x-x_initial;
x = MAX(0,x);
x = MIN(x,winSize.width/2+40);
myMenu.position=ccp(x,180);
x_initial=location.x;
}
}
- (void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
draggingMenu=0;
}
- (void)dealloc {
[super dealloc];
}
#end
Solved it by adding :
-(void) registerWithTouchDispatcher
{
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:INT_MIN+1 swallowsTouches:NO];
}
the problem was that CCMenuItemImage swallows the touches and has a high priority set at -128. Thus the need to set priority at INT_MIN+1
My problem is that I didn't find a solution to "pierce" through a UIScrollView so the ccLayer could recognize the ccTouch events
self.isTouchEnabled = YES;
[[NSBundle mainBundle] loadNibNamed:#"myLayer" owner:self options:nil];
...
- (void) registerWithTouchDispatcher {
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:INT_MIN swallowsTouches:NO];
}
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint location = [self convertToWorldSpace:[self convertTouchToNodeSpace:touch]];
Any ideas how to create a delegate or another solution to bypass the UI and talk with the cc?
I had this problem this morning with Cocos2D v1.0.0. My solution was to include the CCTouchDispatcher method call inside my init method for the layer, and then that layer, inside a UIView, would recognize touches.
-(id) init
{
if ((self = [super init]) != nil) {
// do stuff
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
}
return self;
}
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint location = [self convertToNodeSpace:[[CCDirector sharedDirector] convertToGL:[touch locationInView:[touch view]]]];
NSLog(#"TouchBegan at x:%0.2f, y:%0.2f", location.x, location.y);
return YES;
}
An alternative solution would be to use the ccTouchesBegan method:
-(id) init
{
if ((self = [super init]) != nil) {
// do stuff
self.isTouchEnabled = YES;
}
return self;
}
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *thisTouch in touches) {
CGPoint location = [self convertToNodeSpace:[[CCDirector sharedDirector] convertToGL:[thisTouch locationInView:[thisTouch view]]]];
NSLog(#"TouchesBegan at x:%0.2f, y:%0.2f", location.x, location.y);
}
}
Note that the two touch methods have different methods to let your application know it should respond to touches. You can't mix and match how you want to respond to touches, and which touches you want to observe.