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
Related
I have a cocoa app with a window containing an NSTableView. Each row has a few columns, three radio boxes and two buttons. Currently the table has 260 rows and when the window is focused the scrolling in the table view is atrociously slow and jittery. When the window is not focused and I mouse over the table view and scroll it's buttery smooth.
I've tried to solve the slow performance by changing the background drawing and enabling CoreAnimation Layer to no avail.
Why would the scrolling be fast when the window isn't focused but slow when it is?
I'm just baffled as to why the scrolling is so darn slow.
Here's my ProposalTableViewController.h
#import <Cocoa/Cocoa.h>
#import <Foundation/Foundation.h>
#import <QuickLook/QuickLook.h>
#import <Quartz/Quartz.h>
#interface ProposalTableViewController : NSObject<NSTableViewDataSource, NSTableViewDelegate, QLPreviewPanelDelegate, QLPreviewPanelDataSource>{
#public
NSMutableArray *list;
IBOutlet NSTableView *tableView;
IBOutlet NSSearchField *searchText;
IBOutlet NSTextField *countTextField;
}
#property (strong) QLPreviewPanel *previewPanel;
+ (ProposalTableViewController *)getInstance;
- (IBAction)deleteRow:(id)sender;
- (IBAction)exportData:(id)sender;
- (void)loadData;
- (void)countItems;
#end
And my ProposalTableViewController.m
#import "ProposalTableViewController.h"
#import "Proposal.h"
#import "StatusRadioView.h"
#import "DBManager.h"
#import "filePathButtonView.h"
#import <Quartz/Quartz.h>
#import "AppDelegate.h"
#implementation Proposal (QLPreviewItem)
- (NSURL *)previewItemURL
{
return [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#.pdf",self.filePath]];
}
- (NSString *)previewItemTitle
{
return [NSString stringWithFormat:#"Proposal %#",self.proposalNumber];
}
#end
#implementation ProposalTableViewController
static ProposalTableViewController *instance;
+ (ProposalTableViewController *)getInstance{
return instance;
}
//------------------------------------------------------------------------------------------------------------------------------------
// Init
//------------------------------------------------------------------------------------------------------------------------------------
- (id)init{
self = [super init];
if(self){
instance = self;
list = [[NSMutableArray alloc] init];
[self loadData];
for (NSTableColumn *tableColumn in tableView.tableColumns ) {
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:tableColumn.identifier ascending:YES selector:#selector(compare:)];
[tableColumn setSortDescriptorPrototype:sortDescriptor];
}
}
return self;
}
//------------------------------------------------------------------------------------------------------------------------------------
// Load Data from SQLite
//------------------------------------------------------------------------------------------------------------------------------------
- (void)loadData {
list = [[DBManager getProposalTable] select:#""];
NSSortDescriptor* desc = [[NSSortDescriptor alloc] initWithKey:#"proposalNumber" ascending:NO selector:#selector(compare:)];
[list sortUsingDescriptors:[NSArray arrayWithObjects:desc, nil]];
[tableView reloadData];
[self countItems: list];
}
//------------------------------------------------------------------------------------------------------------------------------------
// Number of Rows in Table View
//------------------------------------------------------------------------------------------------------------------------------------
- (NSInteger) numberOfRowsInTableView:(NSTableView *)tableView {
return [list count];
}
-(void)countItems:(NSArray *)list; {
NSString *countText;
int size = [list count];
if (size == 1){
countText = #"item in list";
}else{
countText = #"items in list";
}
NSString *itemCount = [NSString stringWithFormat:#"%d %#", size, countText];
[countTextField setStringValue:itemCount];
}
//------------------------------------------------------------------------------------------------------------------------------------
// Get View for Table Column
//------------------------------------------------------------------------------------------------------------------------------------
- (NSView *)tableView:(NSTableView *)table_view viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
Proposal *p = [list objectAtIndex:row];
NSString *identifier = [tableColumn identifier];
NSString *holdingValue;
NSTableCellView *cell = [table_view makeViewWithIdentifier:identifier owner:self];
if([identifier isEqualToString:#"status"]){
StatusRadioView *radioView = [[StatusRadioView alloc] initWithProposal:p];
return radioView;
}else if ([identifier isEqualToString:#"filePath"]){
filePathButtonView *buttonView = [[filePathButtonView alloc]initWithProposal:p];
return buttonView;
}else if ([identifier isEqualToString:#"clientAccessPoint"]){
holdingValue = [p valueForKey:identifier];
if (!holdingValue){
cell.textField.stringValue = #"N/A";
}else{
cell.textField.stringValue = [p valueForKey:identifier];
}
}else{
cell.textField.stringValue = [p valueForKey:identifier];
}
return cell;
}
//------------------------------------------------------------------------------------------------------------------------------------
// Sort Descriptors did Change
//------------------------------------------------------------------------------------------------------------------------------------
-(void)tableView:(NSTableView *)mtableView sortDescriptorsDidChange:(NSArray *)oldDescriptors {
[list sortUsingDescriptors: [mtableView sortDescriptors]];
[tableView reloadData];
}
//table row height
-(CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row {
return 25;
}
//------------------------------------------------------------------------------------------------------------------------------------
// Search Text did Change
//------------------------------------------------------------------------------------------------------------------------------------
- (void)controlTextDidChange:(NSNotification *)notification {
NSSortDescriptor* desc = [[NSSortDescriptor alloc] initWithKey:#"proposalNumber" ascending:NO selector:#selector(compare:)];
NSTextField *textField = [notification object];
NSString *str = [textField stringValue];
list = [[DBManager getProposalTable] select:str];
[list sortUsingDescriptors:[NSArray arrayWithObjects:desc, nil]];
[tableView reloadData];
[self countItems: list];
}
//------------------------------------------------------------------------------------------------------------------------------------
// Export DATA
//------------------------------------------------------------------------------------------------------------------------------------
- (IBAction)exportData:(id)sender{
NSString *content = #"";
for(Proposal *p in list){
NSString *row = [NSString stringWithFormat:#"%#,%#,%#,%#,%#,%#,%#,%#,%#,%#", p.proposalNumber,p.itemNumber,p.clientName,p.medium,p.support,p.cost,p.dateCreated,p.status,p.dateStatusChanged,p.clientAccessPoint];
row = [row stringByReplacingOccurrencesOfString:#"\n" withString:#""];
row = [NSString stringWithFormat:#"%#\n", row];
content = [content stringByAppendingString:row];
}
//get the documents directory:
NSString *documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:#"Baumgartner Fine Art Restoration"];
NSString *fileName = [documentsDirectory stringByAppendingPathComponent:#"proposalBuilderDatabase.csv"];
[[NSFileManager defaultManager] createDirectoryAtPath:documentsDirectory
withIntermediateDirectories:NO
attributes:nil
error:nil];
[content writeToFile:fileName
atomically:NO
encoding:NSStringEncodingConversionAllowLossy
error:nil];
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:#"Export Succeeded"];
[alert addButtonWithTitle:#"Ok"];
[alert runModal];
}
//------------------------------------------------------------------------------------------------------------------------------------
// Delete row from DB and table
//------------------------------------------------------------------------------------------------------------------------------------
- (IBAction)deleteRow:(id)sender{
NSString *row = list[tableView.selectedRow];
NSString *mid = [row valueForKey:#"m_id"];
ProposalTable *deleteRow = [[ProposalTable alloc] init];
[deleteRow deleteWithId: mid];
[self loadData];
[tableView reloadData];
}
//------------------------------------------------------------------------------------------------------------------------------------
// QuickLook
//------------------------------------------------------------------------------------------------------------------------------------
- (NSInteger)numberOfPreviewItemsInPreviewPanel:(QLPreviewPanel *)panel {
return [list count];
}
- (id <QLPreviewItem>)previewPanel:(QLPreviewPanel *)panel previewItemAtIndex:(NSInteger)index {
return list[tableView.selectedRow];
}
- (BOOL)previewPanel:(QLPreviewPanel *)panel handleEvent:(NSEvent *)event {
// redirect all key down events to the table view
if ([event type] == NSKeyDown) {
[tableView keyDown:event];
return YES;
}
return NO;
}
// This delegate method provides the rect on screen from which the panel will zoom.
- (NSRect)previewPanel:(QLPreviewPanel *)panel sourceFrameOnScreenForPreviewItem:(id <QLPreviewItem>)item {
return NSZeroRect;
}
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)rowIndex {
[[QLPreviewPanel sharedPreviewPanel]reloadData];
return YES;
}
#end
Here's my ProposalTableView.h
#import <Cocoa/Cocoa.h>
#interface ProposalTableView : NSTableView
#end
And my ProposalTableView.m
#import "ProposalTableView.h"
#import "AppDelegate.h"
#implementation ProposalTableView
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
self.wantsLayer = YES;
// Drawing code here.
}
- (void)keyDown:(NSEvent *)theEvent
{
NSString *key = [theEvent charactersIgnoringModifiers];
if ([key isEqual:#" "])
{
[[NSApp delegate] togglePreviewPanel:self];
}
else
{
[super keyDown:theEvent];
}
}
#end
There's also code that establishes the SqLite DB connection and interacts with the DB to get the records or delete etc... but that's not really needed here... I also have code that draws the radio buttons and the other buttons but again, I don't think that's necessary unless someone thinks that the drawing is creating the slowdown...?
So it turns out that the drawing of the radio buttons is what is causing the slowdown... back to the drawing board.
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
I am trying to implement an undo/redo method using NSUndoManager. I have asked other questions on this, but am still stuck.
Where I am at the moment is as follows:
.h
NSUndoManager *undoManager;
#property(nonatomic,retain) NSUndoManager *undoManager;
.m
#synthesize undoManager;
[undoManager setLevelsOfUndo:99];
viewdidload:
NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
[dnc addObserver:self selector:#selector(undoButtonTapped) name:#"undo" object:nil];
[dnc addObserver:self selector:#selector(redoButtonTapped) name:#"redo" object:nil];
- (void)resetTheImage:(UIImage*)image
{
NSLog(#"%s", __FUNCTION__);
// image = savedImage.image;
if (image != drawImage.image)
{
[[undoManager prepareWithInvocationTarget:self] resetTheImage];
image = drawImage.image ;
} else {
NSLog(#"That didn't work");
}
}
- (void)undoButtonTapped {
NSLog(#"%s", __FUNCTION__);
[undoManager undo];
}
I get "That didn't work"...
I would appreciate help. I will post the answer to my original question when I figure out what I'm doing wrong.
---EDIT---
I have changed resetTheImage as follows:
- (void)resetTheImage:(UIImage*)image
{
NSLog(#"%s", __FUNCTION__);
image = savedImage.image;
if (image != drawImage.image)
{
drawImage.image = image;
savedImage.image = image;
NSLog(#"undo image");
[[self.undoManager prepareWithInvocationTarget:drawImage.image] image];
} else {
NSLog(#"same image");
savedImage.image = image;
}
}
However, confusion rains - it may help if someone (Brad?, Justin?) can provide a bullet point list of the steps I need to take to get this working. For example:
. Add notifications in ...
. Trigger notifications....
. Have undo /redo buttons point to...
. What methods/functions I really need to build..
....
I wish SO would allow me to give you more points than 1..
(It doesn't help that my "o" key is getting wonky)
It does help that I had a baby granddaughter yesterday :))))
First, I want to thank everyone for any/all assistance. I solved this finally although I'm not sure if it's the best solution.
I made a UIView called from the UIViewController. The controls (colors and brushes) remain in the VC. The drawing methods move to the View Method.
The View Method calls a Drawing method to actually perform the draw, and the View method controls the undo/redo.
Here are some code snippets:
-(void)undoButtonClicked
{
//NSLog(#"%s", __FUNCTION__);
if ([self.currentArray count] == 0) {
//nothing to undo
return;
}
DrawingPath *undonePath = [self.currentArray lastObject];
[self.currentArray removeLastObject];
[self.redoStack addObject:undonePath];
[self setNeedsDisplay];
}
-(void)redoButtonClicked
{
//NSLog(#"%s", __FUNCTION__);
if ([self.redoStack count] == 0) {
// nothing to redo
return;
}
DrawingPath *redonePath = [self.redoStack lastObject];
[self.redoStack removeLastObject];
[self.currentArray addObject:redonePath];
[self setNeedsDisplay];
}
Let me know if anyone wants clarification. Thanks all again..
UPDATE as requested:
These are some headers:
DrawingViewController *mvc;
NSMutableArray *pathArray;
NSMutableArray *colorArray;
NSMutableArray *bufferArray;
NSMutableArray *currentArray;
UIBezierPath *myPath;
NSString *brushSize;
CGPoint lastPoint;
int colorIndex;
NSString *colorKey;
SoundEffect *erasingSound;
SoundEffect *selectSound;
BOOL swiped;
int moved;
UIColor *currentColor;
NSString *result;
}
#property(nonatomic,assign) NSInteger undoSteps;
#property (strong, nonatomic) NSString *result;
#property (strong,nonatomic) UIColor *currentColor;
#property (strong,nonatomic) NSMutableArray *currentArray;
#property (strong,nonatomic) NSMutableArray *bufferArray;
#property (strong,nonatomic) DrawingPath *currentColoredPath;
#property (strong,nonatomic) NSMutableArray *redoStack;
#property (strong, nonatomic) NSString *colorKey;
and here are some more of the methods.. The currentArray then keeps track of points, brush and color in a sort of stack. Undo removes from the stack, and adds into a temp stack that can be used to Redo.
-(void)undoButtonClicked
{
//NSLog(#"%s", __FUNCTION__);
if ([self.currentArray count] == 0) {
//nothing to undo
return;
}
DrawingPath *undonePath = [self.currentArray lastObject];
[self.currentArray removeLastObject];
[self.redoStack addObject:undonePath];
[self setNeedsDisplay];
}
-(void)redoButtonClicked
{
//NSLog(#"%s", __FUNCTION__);
if ([self.redoStack count] == 0) {
// nothing to redo
return;
}
DrawingPath *redonePath = [self.redoStack lastObject];
[self.redoStack removeLastObject];
[self.currentArray addObject:redonePath];
[self setNeedsDisplay];
}
#pragma mark - Touch Methods
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//NSLog(#"%s", __FUNCTION__);
self.currentColoredPath = [[DrawingPath alloc] init];
[self.currentColoredPath setColor:self.currentColor];
UITouch *touch= [touches anyObject];
[self.currentColoredPath.path moveToPoint:[touch locationInView:self]];
[self.currentArray addObject:self.currentColoredPath];
// Remove all paths from redo stack
[self.redoStack removeAllObjects];
lastPoint = [touch locationInView:self];
lastPoint.y -= 20;
if ([touch tapCount] == 2) {
[self alertOKCancelAction];
return;
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
//NSLog(#"%s", __FUNCTION__);
UITouch *touch = [touches anyObject];
[self.currentColoredPath.path addLineToPoint:[touch locationInView:self]];
[self setNeedsDisplay];
CGPoint currentPoint = [touch locationInView:self];
currentPoint.y -= 20;
lastPoint = currentPoint;
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//NSLog(#"%s", __FUNCTION__);
self.currentColoredPath = nil;
}
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.
I need to find my current location with CoreLocation, I tried multiple methods but so far my CLLocationManager has only returned 0's.. (0.000.00.000).
Here's my code (updated to work):
Imports:
#import <CoreLocation/CoreLocation.h>
Declared:
IBOutlet CLLocationManager *locationManager;
IBOutlet UILabel *latLabel;
IBOutlet UILabel *longLabel;
Functions:
- (void)getLocation { //Called when needed
latLabel.text = [NSString stringWithFormat:#"%f", locationManager.location.coordinate.latitude];
longLabel.text = [NSString stringWithFormat:#"%f", locationManager.location.coordinate.longitude];
}
- (void)viewDidLoad {
locationManager = [[CLLocationManager alloc] init];
locationManager.distanceFilter = kCLDistanceFilterNone; // whenever we move
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; // 100 m
[locationManager startUpdatingLocation];
}
You can find your location using CoreLocation like this:
import CoreLocation:
#import <CoreLocation/CoreLocation.h>
Declare CLLocationManager:
CLLocationManager *locationManager;
Initialize the locationManager in viewDidLoad and create a function that can return the current location as an NSString:
- (NSString *)deviceLocation {
return [NSString stringWithFormat:#"latitude: %f longitude: %f", locationManager.location.coordinate.latitude, locationManager.location.coordinate.longitude];
}
- (void)viewDidLoad
{
locationManager = [[CLLocationManager alloc] init];
locationManager.distanceFilter = kCLDistanceFilterNone; // whenever we move
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; // 100 m
[locationManager startUpdatingLocation];
}
And calling the deviceLocation function will return the location as expected:
NSLog(#"%#", [self deviceLocation]);
This is just an example. Initializing CLLocationManager without the user being ready for it isn't a good idea. And, of course, locationManager.location.coordinate can be used to get latitude and longitude at will after CLLocationManager has been initialized.
Don't forget to add the CoreLocation.framework in your project settings under the Build Phases tab (Targets->Build Phases->Link Binary).
With CLLocationManager you don't necessary get the location information immediately. The GPS and other devices that obtain location information might not be initialized. They can take a while before they have any information. Instead you need to create a delegate object that responds to locationManager:didUpdateToLocation:fromLocation: and then set it as the delegate of the location manager.
see here
Here you can show current location with annotation details
in ViewController.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
//My
#import <MapKit/MapKit.h>
#import <MessageUI/MFMailComposeViewController.h>
#interface ViewController : UIViewController<CLLocationManagerDelegate,MKMapViewDelegate,MFMailComposeViewControllerDelegate>
{
IBOutlet UILabel *lblLatitiude;
IBOutlet UILabel *lblLongitude;
IBOutlet UILabel *lblAdress;
}
//My
#property (nonatomic, strong) IBOutlet MKMapView *mapView;
-(IBAction)getMyLocation:(id)sender;
#end
in ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController{
CLLocationManager *locationManager;
CLGeocoder *geocoder;
CLPlacemark *placemark;
}
#synthesize mapView;
- (void)viewDidLoad
{
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
geocoder = [[CLGeocoder alloc] init];
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *defaultsDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:#"pradipvdeore#gmail.com", #"fromEmail",
#"pavitrarupani89#gmail.com", #"toEmail",
#"smtp.gmail.com", #"relayHost",
#"mobileapp.qa#gmail.com", #"login",
#"mobile#123", #"pass",
[NSNumber numberWithBool:YES], #"requiresAuth",
[NSNumber numberWithBool:YES], #"wantsSecure", nil];
[userDefaults registerDefaults:defaultsDictionary];
self.mapView.delegate=self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Custom Methods
-(IBAction)getMyLocation:(id)sender{
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
lblLongitude.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
lblLatitiude.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
}
// Stop Location Manager
[locationManager stopUpdatingLocation];
// Reverse Geocoding
NSLog(#"Resolving the Address");
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
NSLog(#"Found placemarks: %#, error: %#", placemarks, error);
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
lblAdress.text = [NSString stringWithFormat:#"%# %#\n%# %#\n%#\n%#",
placemark.subThoroughfare, placemark.thoroughfare,
placemark.postalCode, placemark.locality,
placemark.administrativeArea,
placemark.country];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(currentLocation.coordinate, 800, 800);
[self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];
// Add an annotation
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = currentLocation.coordinate;
point.title = #"Where am I?";
point.subtitle = [NSString stringWithFormat:#"%# %#\n%# %#\n%#\n%#",
placemark.subThoroughfare, placemark.thoroughfare,
placemark.postalCode, placemark.locality,
placemark.administrativeArea,
placemark.country];
[self.mapView addAnnotation:point];
} else {
NSLog(#"%#", error.debugDescription);
}
} ];
}
//My
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"loc"];
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return annotationView;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
[self getSignScreenShot];
MFMailComposeViewController* controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
[controller setSubject:#"My Subject"];
[controller setMessageBody:#"Hello there." isHTML:NO];
if (controller) [self presentModalViewController:controller animated:YES];
}
- (void)mailComposeController:(MFMailComposeViewController*)controller
didFinishWithResult:(MFMailComposeResult)result
error:(NSError*)error;
{
if (result == MFMailComposeResultSent) {
NSLog(#"It's away!");
}
[self dismissModalViewControllerAnimated:YES];
}
//-----------------------------------------------------------------------------------
//This methos is to take screenshot of map
//-----------------------------------------------------------------------------------
-(UIImage *)getSignScreenShot
{
CGRect rect = CGRectMake(self.mapView.frame.origin.x,self.mapView.frame.origin.y-50,self.mapView.frame.size.width+60,self.mapView.frame.size.height+15);
UIGraphicsBeginImageContextWithOptions(self.mapView.frame.size, NO, 1.0);
[self.mapView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
CGImageRef imageRef = CGImageCreateWithImageInRect([screenshot CGImage], rect);
UIImage *newImage = [UIImage imageWithCGImage:imageRef];
return newImage;
}