I think I may have discovered a bug in the mapkit API for iOS 6, but since I still consider myself a rookie I thought I'd check here to see if anyone can point out something I may be doing wrong.
I have an app that I've been working on for a few weeks with a mapview in it and utilizing the MKUserTrackingButton to toggle tracking modes. On iOS 5 it was working fine but since upgrading to 6 it has weird behavior. When you put the mapview into The tracking mode that follows user with heading, it does fine if you are relatively stationary, but when you start moving in a car it drops out of the track with heading mode every time back to regular tracking mode. After many frustrating hours trying to figure it out I decided to make a new simple app with the bare minimum mapview and tracking to see if it was just my coding or possible bug. The new app does the same thing. I'm posting all the code below. Hopefully some one can help tell me if I'm doing something wrong or not.
Here's the app delegate header
// iTrackerAppDelegate.h
// iTracker
//
// Created by Victor Hudson on 9/22/12.
// Copyright (c) 2012 Victor Hudson. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "TrackerViewController.h"
#interface iTrackerAppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) IBOutlet UIWindow *window;
#end
Here's the app delegate implementation
//
// iTrackerAppDelegate.m
// iTracker
//
// Created by Victor Hudson on 9/22/12.
// Copyright (c) 2012 Victor Hudson. All rights reserved.
//
#import "iTrackerAppDelegate.h"
#implementation iTrackerAppDelegate
#synthesize window = _window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
TrackerViewController *trackerView = [[TrackerViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc]initWithRootViewController:trackerView];
[self.window setRootViewController:navController];
[[self window] makeKeyAndVisible];
return YES;
}
// the other app delegate methods are all empty so i left them out for brevity
#end
Here's my view controller. It has a nib with the worldView in it and a segmented switch for toggling map modes(plain, sat, and hybrid)
TrackerViewController.h
//
// TrackerViewController.h
// iTracker
//
// Created by Victor Hudson on 9/22/12.
// Copyright (c) 2012 Victor Hudson. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface TrackerViewController : UIViewController
#property (strong, nonatomic) IBOutlet MKMapView *worldView;
- (IBAction)toggleMapView:(id)sender;
#end
TrackerViewController.m
//
// TrackerViewController.m
// iTracker
//
// Created by Victor Hudson on 9/22/12.
// Copyright (c) 2012 Victor Hudson. All rights reserved.
//
#import "TrackerViewController.h"
#interface TrackerViewController ()
#end
#implementation TrackerViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
// navigation item
[[self navigationItem] setTitle:#"iTracker"];
MKUserTrackingBarButtonItem *trackingButton = [[MKUserTrackingBarButtonItem alloc] initWithMapView:self.worldView];
[[self navigationItem] setRightBarButtonItem:trackingButton animated:YES];
self.worldView.userTrackingMode = 1;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)toggleMapView:(id)sender {
switch ([sender selectedSegmentIndex]) {
case 0:
{
[self.worldView setMapType:MKMapTypeStandard];
}break;
case 1:
{
[self.worldView setMapType:MKMapTypeSatellite];
}break;
case 2:
{
[self.worldView setMapType:MKMapTypeHybrid];
}break;
}
}
#end
As I said before all seems to work fine but the tracking with heading mode when you are moving very fast. I am running on an iPhone 4, and Ive tried the app with and without ARC to the same results. I would be grateful if someone can point out any mistakes I'm making or if they want to build the project and can confirm it is a bug.
Thanks in advance for any assistance ;-)
I'm currently investigating a similar behaviour in my app when going from ios5 to ios6.
There is a locationmanager created as a singleton as described in
cllocationmanager singleton
Furthermore in the mapview I'm using setusertrackingmode. In ios6 it jumps from MKUserTrackingModeFollowWithHeading to MKUserTrackingModeFollow back and forth. In ios5 it works fine with identical code.
It may be that the two locationmanagers are in conflict with each other as pointed out in
conflict between two locationmanagers
Related
I have to maintain a quite old and large objective-c project.
Every thing works fine until iOS12 but from iOS13 the scope-button-bar of UISearchBar does not work with UISearchDisplayController.
I know that UISearchDisplayController is deprecated but I really don't want to migrate it to UIDisplayController because of some reasons.
I did some test and find out the problem might related to UIDisplayController as it block the user touch on the scope button.
My code as below:
#implementation MyUISearchDisplayController
- (void)setActive:(BOOL)visible animated:(BOOL)animated
{
if(self.active == visible){ return; }
[self.searchContentsController.navigationController setNavigationBarHidden:YES animated:NO];
[super setActive:visible animated:animated];
[self.searchContentsController.navigationController setNavigationBarHidden:NO animated:NO];
if (visible)
{
[self.searchBar becomeFirstResponder];
}
else
{
[self.searchBar resignFirstResponder];
}
}
#end
#interface TopBarViewController ()
#property (strong, nonatomic) IBOutlet UISearchBar *searchBar;
#property (strong, nonatomic) UISearchDisplayController *searchController;
#end
#implementation TopBarViewController
- (void)viewDidLoad {
[super viewDidLoad];
//The default state for show-cancel-button and show-scope-bar of searchBar is false (not showing)
self.searchBar.scopeButtonTitles = #[#"scope1", #"scope2", #"scope3", #"scope4"];
self.searchController = [[MyUISearchDisplayController alloc] initWithSearchBar:self.searchBar contentsController:self];
self.searchController.delegate = self;
}
The code above works as well until IOS12, but from IOS13 I cannot touch the scope button. I guess the problem related to the UIDisplayController class.
So I'm thinking of overwrite some method of UIDisplayController but don't know how to start. Any body have experience with that. Any information would be appreciated. Thanks.
I'm quite new to Objective-C and IOS, I did a lot of search on google but no luck.
updated:
After some days debugging I solved my problem by overwriting the hitTest method of UISearchBar class. The following should do the trick (also it's not a documented way)
#implementation MyUISearchBar
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
UIView * touchedView = [super hitTest:point withEvent:event];
if(check version stuff){
return touchedView;
}
UIView * scopeBar = [self performSelector:NSSelectorFromString(#"_scopeBar")];
if(user touched the scopeBar){
return scopeBar;
}
return touchedView;
}
Hope it helps some one.
UISearchDisplayController is deprecated, use UISearchController instead.
Look here
https://useyourloaf.com/blog/updating-to-the-ios-8-search-controller/
You must migrate because UISearchDisplayController will not work correctly in iOS13.
Look at this project, is good example how to manage UISearchController.
https://github.com/kharrison/CodeExamples/tree/master/WorldFacts
Good luck
i am a .net programmer and last week i started to read about objective-c. Class related stuff are kinda clear and today i learnt about protocols and delegates, i can't say it is 100% clear but i got it, it looks a lot with delegates and events from c#.
This is a simple example i created following a tutorial. It is all about 2 screens, the first one(a label and a button) launches the second one(a textbox and a button) which sends back a string. I think of it as a classic example of using events, no matter the programming language.
#import <UIKit/UIKit.h>
#import "ValueViewController.h"
#interface ViewController : UIViewController<ValueViewControllerDelegate>
- (IBAction)btnGetValue:(id)sender;
#property (weak, nonatomic) IBOutlet UILabel *lblCurrentValue;
#end
#import "ViewController.h"
#import "ValueViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)btnGetValue:(id)sender {
ValueViewController *valueVC = [self.storyboard instantiateViewControllerWithIdentifier:#"ValueViewController"];
valueVC.delegate=self;
[self presentViewController:valueVC animated:FALSE completion:nil];
}
-(void) sendValue:(ValueViewController *)controller didFihishWithValue:(NSString *)value
{
self.lblCurrentValue.text=value;
}
#end
#import <UIKit/UIKit.h>
#class ValueViewController;
#protocol ValueViewControllerDelegate<NSObject>
-(void) sendValue:(ValueViewController*) controller didFihishWithValue:(NSString*) value;
#end
#interface ValueViewController : UIViewController<UITextFieldDelegate>
#property (weak, nonatomic) IBOutlet UITextField *txtValue;
- (IBAction)btnSetValue:(id)sender;
#property (weak, nonatomic) id<ValueViewControllerDelegate> delegate;
#end
#import "ValueViewController.h"
#interface ValueViewController ()
#end
#implementation ValueViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.txtValue.delegate=self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
return [textField resignFirstResponder];
}
- (IBAction)btnSetValue:(id)sender
{
[self.delegate sendValue:self didFihishWithValue:self.txtValue.text];
[self dismissViewControllerAnimated:FALSE completion:nil];
}
#end
My question is the following: Considering a, let's say, 30 screens application, which allows sending and receiving messages, adding friends , etc
Is it a good approach to group those 4-5 message view controller into a storyboard, those friends related view controllers into another storyboard and just make the connection like i did in that simple example, programmatically?
I saw that connections can be done in the designer without writing code, but sometimes i think you have to write code to send some arguments which means mixing the two(graphically and programmatically).
I just feel more comfortable, doing it programatically, maybe because this is how i do it in c#.
I am looking forward to you tips regarding organizing and making connections between screens.
PS: Sorry for writing such a long story(board) in here, i promise to make it shorter in my following posts.
Thanks.
Making two storyboards that communicate with each other would go against the intended flow, because storyboards were not intended for grouping parts of an application. Although an app may definitely have multiple storyboards, the intention behind allowing multiple storyboards was letting you support different screen paradigms (i.e. iPhone vs. iPad) or different localizations, not grouping related screens together.
Note, however, that storyboards are relatively new. You can define your views in NIB files, and use them instead. An unfortunate consequence of this choice is that you would need to make all your connections programmatically, but on the other hand you would be able to group your views inside you Xcode project using file groups or folders.
I have an embedded YoutTube video in my app. The entire app is locked into only running in portrait but I'd like the video to play in landscape once the user taps the play button on the thumbnail. Here is the code for the embedded YouTube video.
//
// YouTubeView.h
// KFBNewsroom
//
// Created by KFB on 11/8/12.
// Copyright (c) 2012 com.kfb. All rights reserved.
//
#import <UIKit/UIKit.h>
#interface YouTubeView : UIViewController
{
IBOutlet UIWebView *thumbnailView;
}
#property (nonatomic, retain) IBOutlet UIWebView *thumbnailView;
#end
//
// YouTubeView.m
// KFBNewsroom
//
// Created by KFB on 11/8/12.
// Copyright (c) 2012 com.kfb. All rights reserved.
//
#import "YouTubeView.h"
#interface YouTubeView ()
#end
#implementation YouTubeView
#synthesize thumbnailView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"Monthly Video";
// Do any additional setup after loading the view from its nib.
// webView is a UIWebView, either initialized programmatically or loaded as part of a xib.
NSString *htmlString = #"<html><head><meta name = \"viewport\" content = \"initial-scale = 1.0, user-scalable = no, width = 280\"/></head><body style=\"background:#F00;margin-top:0px;margin-left:0px\"><div><object width=\"280\" height=\"218\"><param name=\"movie\" value=\"http://www.youtube.com/embed/videoseries?list=PL0B9BF37A24840E28&hl=en_US""></param><param name=\"wmode\" value=\"transparent\"></param><embed src=\"http://www.youtube.com/embed/videoseries?list=PL0B9BF37A24840E28&hl=en_US""type=\"application/x-shockwave-flash\" wmode=\"transparent\" width=\"280\" height=\"218\"></embed></object></div></body></html>";
[thumbnailView loadHTMLString:htmlString baseURL:[NSURL URLWithString:#"http://www.youtube.com/playlist?list=PL0B9BF37A24840E28&feature=plcp"]];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
To receive the notification that your device is rotated you need to set your project configuration to use also landscape modes. Then if you have your UIViewController class, you need to implement rotation to ignore everything besides portrait. In controller where you have your video, you just override it to accept landscape too.
I have a very simple project. Extremely watered down. All it does is load some text into an NSTableView. That's it. But it's using a new window and controller, called "Revisions."
As soon as the new window becomes active, it crashes or just locks up. No errors in the console. If it sits in the background, behind the AppDelegate's window, it appears to load the information fine. I can see the table is populated perfectly. But as soon as I click on the window and make it active, it crashes/locks.
This is driving me nuts. I know it has to do with memory management, but I can't figure out where or how or why.
Note, I'm in XCode 4.2, where there's no more releasin' (unless I change some settings, of course).
All connections in
AppDelegate.h
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (assign) IBOutlet NSWindow *window;
#end
AppDelegate.m
#import "AppDelegate.h"
#import "Revisions.h"
#implementation AppDelegate
#synthesize window = _window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
Revisions *rev = [[Revisions alloc] initWithWindowNibName:#"Revisions"];
[rev loadWindow];
}
Revisions.h
#import <Cocoa/Cocoa.h>
#interface Revisions : NSWindowController
{
IBOutlet NSTableView *quicktimesList;
IBOutlet NSTableView *unusedDataList;
}
#end
Revisions.m
#import "Revisions.h"
#implementation Revisions
- (id)initWithWindow:(NSWindow *)window
{
self = [super initWithWindow:window];
if (self) {
// Initialization code here.
}
return self;
}
- (void)windowDidLoad
{
[super windowDidLoad];
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
{
NSLog(#"Creating number of rows.");
return 10;
}
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
{
NSLog(#"Starting Loop.");
NSString *words = [[NSString alloc] initWithFormat:#"Row %i", rowIndex];
NSLog(#"Looping %i", (int)rowIndex);
return words;
}
#end
Ok. I'm going to give you a couple of tips when dealing with potential memory leaks in Xcode 4.2.
When writing software for Mac it is advisable to enable garbage collection in your build settings. Just simply search for "garbage collection" in the search bar of your build settings and set it to "required".
If you have memory leaks in your project just press the "product" menu and hit "Analyze".This does as the menu item states, it analyses your project for potential memory leaks and helps you track them down.
Hope this helps!
I'm realizing what a newbie I still am with this problem I have. I am trying to present a modal window in a project I am working on and it's not appearing. My solution was then to create an absolute basic project and get it working there first, so I would clearly understand my problem, but I can't get even this working :(
I add a ViewController to the MainWindow at applicationDidFinishLaunching. In this ViewControllers XIB, I have a button. The ViewController has the following header:
#import <UIKit/UIKit.h>
#import "ModalView.h"
#interface ViewBasedViewController : UIViewController {
ModalView *modalView;
}
- (IBAction)dooooIt :(id)sender;
#property (nonatomic, retain, readonly) ModalView *modalView;
#end
And methods:
#import "ViewBasedViewController.h"
#implementation ViewBasedViewController
#synthesize modalView;
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
}
- (void)dealloc {
[super dealloc];
[modalView release];
}
- (ModalView *)modalView {
if (modalView == nil) {
modalView = [[ModalView alloc] initWithNibName:#"ModalView" bundle:nil];
}
return modalView;
}
- (IBAction)dooooIt :(id)sender {
[self.navigationController presentModalViewController:modalView animated:YES];
}
#end
I'm obviously missing something very simple and I believe it's between my ears at this stage :)
Does anyone want to put a poor fella out of his misery?
Many Thanks
Chris
Have you connected the button to the IBAction? Control-drag in Interface Builder from your button to the "File's Owner" icon in your XIB file, and select the "dooooIt" method there. Recompile and your code should execute as expected.
For those that may come across this problem and were as baffled as I was, I fell over the solution. There was two problems in the dooooIt method:
- (IBAction)dooooIt :(id)sender {
[self presentModalViewController:self.modalView animated:YES];
}
I should have included 'self' when referring to the modalView property (otherwise it's nil) and I shouldn't have referred to the navigationController as I had none hooked up.
Hope this helps any of you (amazing what a glass of wine can do! :)