iPhone MapView interrupted - iphone

I have a mapkit / view and it works fine - but I scroll around and after 2 - 10 moves my app crashed... and this only with a "interrupted".
Here is part of my code. I think it's a problem with the background threads and an array release / override problem.
Some background info: I generate a "session" key (MapKey) on mapview startup and save on the serverside a pin. The XML includes only new pins for a faster response and shorter XML.
// Update map when the user interacts with it
- (void)mapView:(MKMapView *)aMapView regionDidChangeAnimated:(BOOL)animated
{
MyAnnotation *annotation = [[MyAnnotation alloc] init];
MyAnnotation *ann = [[MyAnnotation alloc] init];
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSString *postBody = [[[NSString alloc] initWithFormat:#"single=0&lat=%f&lng=%f&sid=%#", mapView.centerCoordinate.latitude, mapView.centerCoordinate.longitude, [prefs stringForKey:#"MapKey"], [prefs stringForKey:#"MapKey"]] autorelease];
[self performSelectorInBackground:#selector(getMark:) withObject:postBody];
}
// make post and interact with verarbeiten
-(void) getMark:(NSString *)postBody
{
NSAutoreleasePool *ccpool = [[NSAutoreleasePool alloc] init];
NSString *urlStr = [[[NSString alloc] initWithFormat:#"http://URL/get.php"] autorelease];
NSMutableURLRequest *request;
NSData *postData = [postBody dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
NSURLResponse *response;
NSData *dataReply;
id stringReply;
request = [NSMutableURLRequest requestWithURL: [NSURL URLWithString:urlStr]];
[request setHTTPMethod: #"POST"];
[request setHTTPBody:postData];
[request setValue:#"text/xml" forHTTPHeaderField:#"Accept"];
dataReply = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
stringReply = (NSString *)[[[NSString alloc] initWithData:dataReply encoding:NSUTF8StringEncoding] autorelease];
[self performSelectorInBackground:#selector(verarbeiten:) withObject:stringReply];
[ccpool release];
}
//generate annotations array with annotations an set it to mapview
-(void) verarbeiten:(NSString *)stringReply
{
NSAutoreleasePool *bbpool = [[NSAutoreleasePool alloc] init];
CXMLDocument *rssParser = [[[CXMLDocument alloc] initWithXMLString:stringReply options:0 error:nil] autorelease];
NSMutableArray* annotations = [[NSMutableArray alloc] init];
NSArray *resultNodes = nil;
resultNodes = nil;
resultNodes = [rssParser nodesForXPath:#"//place" error:nil];
for (CXMLElement *resultElement in resultNodes)
{
MyAnnotation *ann = [[MyAnnotation alloc] init];
ann.title = [[resultElement childAtIndex:3] stringValue];
ann.subtitle = [[resultElement childAtIndex:5] stringValue];
ann.currentPoint = [NSNumber numberWithInt:[[[resultElement childAtIndex:1] stringValue] intValue]];
MKCoordinateRegion region = { {0.0, 0.0 }, { 0.0, 0.0 } };
region.center.latitude = [[[resultElement childAtIndex:9] stringValue] floatValue];
region.center.longitude = [[[resultElement childAtIndex:7] stringValue] floatValue];
ann.coordinate = region.center;
//[mapView addAnnotation:ann ];
[annotations addObject:ann];
}
[mapView addAnnotations:annotations ];
[annotations release];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[bbpool release];
}
- (MKAnnotationView *) mapView:(MKMapView *)mV viewForAnnotation:(MyAnnotation *) annotation
{
MKPinAnnotationView *pinView = nil;
if(annotation != mapView.userLocation)
{
static NSString *defaultPinID = #"de.my.pin";
pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinView == nil )
pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID] autorelease];
pinView.pinColor = MKPinAnnotationColorRed;
pinView.canShowCallout = YES;
pinView.animatesDrop = NO;
pinView.userInteractionEnabled = YES;
UIButton *btnVenue = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
btnVenue.tag = [annotation.currentPoint intValue];
[btnVenue addTarget:self action:#selector(showLinks:) forControlEvents:UIControlEventTouchUpInside];
pinView.rightCalloutAccessoryView = btnVenue;
}
else
{
[mapView.userLocation setTitle:#"You are here"];
}
return pinView;
}
#import "MyAnnotation.h"
#implementation MyAnnotation
#synthesize coordinate, title, subtitle,currentPoint;
-(void)dealloc
{
[title release];
[subtitle release];
[super dealloc];
}
#end
#import <Foundation/Foundation.h>
#import <MapKit/MKAnnotation.h>
#interface MyAnnotation : NSObject <MKAnnotation>
{
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
NSNumber *currentPoint;
}
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#property(nonatomic, retain) NSNumber *currentPoint;
#end

Just a thought: since -[MKMapView addAnnotations:] (potentially) performs UI modifications, you may want to call it in the main thread:
[mapView performSelectorOnMainThread: #selector(addAnnotations:) withObject: annotations waitUntilDone: YES];

Related

I can't add annotations in the mapview by using latitude and longitude

I have read the latitudes and longitudes from an xml file, and I want to add some annotations with them. But except the user location, none of them was added.The count of mapview.annotations is always empty.Here is my code:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
if (newLocation != nil) {
self.myLocation = newLocation;
}
mapView.region = MKCoordinateRegionMake(self.myLocation.coordinate, MKCoordinateSpanMake(0.005f, 0.005f));
mapView.zoomEnabled = YES;
//mapView.showsUserLocation = YES;
mapView.centerCoordinate = self.myLocation.coordinate;
MKPointAnnotation *userLocation = [[MKPointAnnotation alloc] init];
userLocation.coordinate = myLocation.coordinate;
userLocation.title = #"my position";
userLocation.subtitle = #"my position now";
[mapView removeAnnotations:mapView.annotations];
[mapView addAnnotation:userLocation];
[userLocation release];
if ([self.positionArray count] < 5) {
NSString *dataPath = [[NSBundle mainBundle] pathForResource:#"position" ofType:#"xml"];
NSData *positionData = [[NSData alloc] initWithContentsOfFile:dataPath];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:positionData];
parser.delegate = self;
[parser parse];
}
if (self.myLocation != nil) {
[self.manager stopUpdatingLocation];
}
}
And here is the MapInfo class:
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
#interface MapInfo : NSObject<MKAnnotation>
{
NSString *subtitle;
NSString *title;
CLLocationCoordinate2D coordinate;
}
#property (nonatomic, copy) NSString *subtitle;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
- (id)initWithCoordinate:(CLLocationCoordinate2D)location;
- (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate;
#end
Then here is the delegate method
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
static NSString *AnnotationIdentifier = #"AnnotationIdentifer";
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if ([annotation isKindOfClass:[MapInfo class]]) {
if (pinView == nil) {
pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] autorelease];
}
pinView.pinColor = MKPinAnnotationColorRed;
pinView.canShowCallout = YES;
pinView.animatesDrop = NO;
}else if([annotation isKindOfClass:[MKPointAnnotation class]])
{
if (pinView == nil) {
pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] autorelease];
}
pinView.pinColor = MKPinAnnotationColorPurple;
pinView.canShowCallout = YES;
pinView.animatesDrop = NO;
}
return pinView;
}
I really don't know why only the user location can be added,someone help me please!!It has bothered me for several days!
Looks like you may have forgotten to set the mapView's delegate.

Reload JSON Feed within a UIView

I have a mapView that has annotation added through JSON (feed is stored in NSDictionary). Everything works great, but I want to add a feature.
I want the mapView to reload all of the annotations each time the view reappears (every time the tab bar is pressed). T've tried putting the part where the JSON is added to the NSDictionary in viewWillAppear {} .... but it does not work.
My code is below. Thanks in advance!
#import "MapViewController.h"
#import "DisplayMap.h"
#import "JSON/JSON.h"
#implementation MapViewController
#synthesize mapView;
#synthesize selectedType;
#synthesize locationManager;
// JSON from Server Actions
- (NSString *)stringWithUrl:(NSURL *)url {
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReturnCacheDataElseLoad
timeoutInterval:30];
// Fetch the JSON response
NSData *urlData;
NSURLResponse *response;
NSError *error;
// Make synchronous request
urlData = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:&response
error:&error];
// Construct a String around the Data from the response
return [[NSString alloc] initWithData:urlData encoding:NSUTF8StringEncoding];
}
- (id)objectWithUrl:(NSURL *)url {
SBJsonParser *jsonParser = [SBJsonParser new];
NSString *jsonString = [self stringWithUrl:url];
// Parse the JSON into an Object
return [jsonParser objectWithString:jsonString error:NULL];
}
- (NSDictionary *) downloadFeed {
id response = [self objectWithUrl:[NSURL URLWithString:#"http://www.example.com/JSON"]];
NSDictionary *feed = (NSDictionary *)response;
return feed;
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[locationManager startUpdatingLocation];
mapView.mapType = MKMapTypeStandard;
mapView.zoomEnabled = YES;
mapView.scrollEnabled = YES;
mapView.showsUserLocation = YES;
MKCoordinateRegion region = { {0.0, 0.0 }, { 0.0, 0.0 } };
region.span.longitudeDelta = 0.005;
region.span.latitudeDelta = 0.005;
[mapView setRegion:region animated:YES];
[mapView setDelegate:self];
// Download JSON Feed
NSDictionary *feed = [self downloadFeed];
NSArray *streams = (NSArray *)[feed valueForKey:#"stream"];
int Info;
for (Info = 0; Info < streams.count; Info++) {
NSDictionary *stream = (NSDictionary *)[streams objectAtIndex:Info];
NSLog(#"Time: %#", [stream valueForKey:#"Time"]);
NSLog(#"Type: %#", [stream valueForKey:#"Type"]);
NSLog(#"Longitude: %#", [stream valueForKey:#"Longitude"]);
NSLog(#"Latitude: %#", [stream valueForKey:#"Latitude"]);
double lat = [[stream valueForKey:#"Latitude"] doubleValue];
double lon = [[stream valueForKey:#"Longitude"] doubleValue];
NSString *ttype = [[NSString alloc] initWithFormat: #"%#", [stream valueForKey:#"Type"]];
selectedType = ttype;
CLLocationCoordinate2D coord = {lat, lon};
DisplayMap *ann = [[DisplayMap alloc] init];
ann.title = [NSString stringWithFormat: #"%#", [stream valueForKey:#"Type"]];
ann.subtitle = [NSString stringWithFormat: #"%#", [stream valueForKey:#"Time"]];
ann.coordinate = coord;
[mapView addAnnotation:ann];
}
}
}
}
-(void)viewWillAppear { }
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
CLLocationCoordinate2D loc = [newLocation coordinate];
[mapView setCenterCoordinate:loc];
}
-(IBAction)refreshMap:(id)sender {
// Download JSON Feed
NSDictionary *feed = [self downloadFeed];
NSArray *streams = (NSArray *)[feed valueForKey:#"stream"];
int Info;
for (Info = 0; Info < streams.count; Info++) {
NSDictionary *stream = (NSDictionary *)[streams objectAtIndex:Info];
NSLog(#"Time: %#", [stream valueForKey:#"Time"]);
NSLog(#"Type: %#", [stream valueForKey:#"Type"]);
NSLog(#"Longitude: %#", [stream valueForKey:#"Longitude"]);
NSLog(#"Latitude: %#", [stream valueForKey:#"Latitude"]);
double lat = [[stream valueForKey:#"Latitude"] doubleValue];
double lon = [[stream valueForKey:#"Longitude"] doubleValue];
NSString *ttype = [[NSString alloc] initWithFormat: #"%#", [stream valueForKey:#"Type"]];
selectedType = ttype;
CLLocationCoordinate2D coord = {lat, lon};
DisplayMap *ann = [[DisplayMap alloc] init];
ann.title = [NSString stringWithFormat: #"%#", [stream valueForKey:#"Type"]];
ann.subtitle = [NSString stringWithFormat: #"%#", [stream valueForKey:#"Time"]];
ann.coordinate = coord;
[mapView addAnnotation:ann];
}
}
-(MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil; //return nil to use default blue dot view
static NSString *AnnotationViewID = #"annotationViewID";
MKAnnotationView *annotationView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationViewID];
if (annotationView == nil) {
annotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID] autorelease];
}
annotationView.canShowCallout = YES;
if ([annotationView.annotation.title isEqualToString:#"Selected"]) {
UIImage *pinImage = [UIImage imageNamed:#"icon_selected.png"];
[annotationView setImage:pinImage];
}
annotationView.annotation = annotation;
return annotationView;
}
- (void)dealloc {
[mapView release];
self.adView.delegate = nil;
self.adView = nil;
[super dealloc];
}
#end
From UIViewController.h:
- (void)viewWillAppear:(BOOL)animated;
viewWillAppear is not the same as viewWillAppear:. Perhaps if you override the proper method it might work?
I think more details are needed. If viewWillAppear is not getting called then it is probably something to do with the way you are setting up the views.
These two links should give you some pointers.
How do I have a view controller run updating code when it is brought to the top of the stack of views?
and
What's the proper way to add a view controller to the view hierarchy?

Place Annotations on Map with NSDictionary?

Thanks for the help in advance... this one has been killing me for the past couple of hours.
I am currently pulling in a JSON feed and storing it in a NSDictionary & NSArray. I'm trying to add an annotation for each item being pulled in (time, type, latitude, and longitude). So far, I can extract each value from the Array and have them all repeat with a "for" in the console (see code below).
How to I store these values as an annotation? Any help would be great.
Below is my failed attempt...
- (void)viewDidLoad {
[super viewDidLoad];
// Download JSON Feed
NSDictionary *feed = [self downloadFeed];
NSArray *streams = (NSArray *)[feed valueForKey:#"stream"];
[mapView setMapType:MKMapTypeStandard];
[mapView setZoomEnabled:YES];
[mapView setScrollEnabled:YES];
MKCoordinateRegion region = { {0.0, 0.0 }, { 0.0, 0.0 } };
region.center.latitude = 29.719023;
region.center.longitude = -114.157110;
region.span.longitudeDelta = 0.01f;
region.span.latitudeDelta = 0.01f;
[mapView setRegion:region animated:YES];
[mapView setDelegate:self];
int Info;
for (Info = 0; Info < streams.count; Info++) {
NSDictionary *stream = (NSDictionary *)[streams objectAtIndex:Info];
NSLog(#"Time: %#", [stream valueForKey:#"TheTime"]);
NSLog(#"Type: %#", [stream valueForKey:#"Type"]);
NSLog(#"Longitude: %#", [stream valueForKey:#"Longitude"]);
NSLog(#"Latitude: %#", [stream valueForKey:#"Latitude"]);
NSString *getLat = [[NSString alloc] initWithFormat: #"%#", [stream valueForKey:#"Latitude"]];
NSString *getLong = [[NSString alloc] initWithFormat: #"%#", [stream valueForKey:#"Longitude"]];
NSString *getCoord = [[NSString alloc] initWithFormat: #"{%#,%#}", getLat, getLong];
getCoordinates = getCoord;
DisplayMap *ann = [[DisplayMap alloc] init];
ann.title = #"%#", [stream valueForKey:#"TheTime"];
ann.subtitle = #"%#", [stream valueForKey:#"Type"];
ann.coordinate = getCoordinates;
[mapView addAnnotation:ann];
}
}
Here is the code for DisplayMap
DisplayMap.h
#import <Foundation/Foundation.h>
#import <MapKit/MKAnnotation.h>
#interface DisplayMap : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#end
And now DisplayMap.m
#import "DisplayMap.h"
#implementation DisplayMap
#synthesize coordinate;
#synthesize title;
#synthesize subtitle;
-(void)dealloc{
[title release];
[super dealloc];
}
#end
What type is getCoordinates? Whatever the case, its definitely not being initialized right.
Assuming that your storing Latitude and Longitude as strings in your dictionary, this should do the trick.
double lat = [[stream valueForKey:#"Latitude"] doubleValue];
double lon = [[stream valueForKey:#"Longitude"] doubleValue];
CLLocationCoordinate2D coord = { lat, lon };
DisplayMap *ann = [[DisplayMap alloc] init];
ann.title = [stream valueForKey:#"TheTime"];
ann.subtitle = [stream valueForKey:#"Type"];
ann.coordinate = coord;
[mapView addAnnotation:ann];
At first glance :
ann.title = #"%#", [stream valueForKey:#"TheTime"];
should be
ann.title = [NSString stringWithFormat: #"%#", [stream valueForKey:#"TheTime"]];
I guess

mapkit , tagging a disclosure button with index of annotation

i have been struggling with this for a few days, i even re-wrote half the code to try it another way.
i have my annotations imported from a csv, and placed onto the map with tile and subtitle, i am trying in vain to add a tag to disclosue buttons so i can see which one was tapped, but having problems, whatever values i assign to the annotation i cant seem to access them (like the index) i can access the title and subtitle, but thats it.
how do i assign a index to the annotation that i can then add to the button as a tag, so i can record the tap
here is my code
NSURL *dataUrl = [NSURL URLWithString:#"http://nne.ezadspro.co.uk/cms/testmap.txt"];
// URLWithString:#"http://neic.usgs.gov/neis/gis/qed.asc"];
NSString *fileString = [NSString stringWithContentsOfURL:dataUrl
encoding:NSUTF8StringEncoding
error:nil];
int count = 0;
NSScanner *scanner = [NSScanner scannerWithString:fileString];
points = [[NSMutableArray array] retain];
AnnotationData *event;
NSString *line;
NSArray *values;
while ([scanner isAtEnd] == NO) {
[scanner scanUpToString:#"\n" intoString:&line];
//skip the first line
if(count > 0) {
values = [line componentsSeparatedByString:#","];
event = [[[AnnotationData alloc] init] autorelease];
event.latitude = [[values objectAtIndex:5] floatValue];
event.longitude = [[values objectAtIndex:6] floatValue];
event.companyID = [[values objectAtIndex:0]intValue];
event.title = [values objectAtIndex:1];
event.subtitle = [values objectAtIndex:2];
//event.magnitude = [[values objectAtIndex:4] floatValue];
//event.depth = [[values objectAtIndex:5] floatValue];
//NSLog(#"%#",event.companyID);
[points addObject:event];
}
count++;
if(count == 300) {
//limit number of events to 300
break;
}
}
for (int i=0; i<points.count; i++) {
AnnotationData *annData = [points objectAtIndex:i];
coordinate.latitude = annData.latitude;
coordinate.longitude = annData.longitude;
CLLocationCoordinate2D newCoord = {coordinate.latitude, coordinate.longitude};
PlaceAnnotation* annotation = [[PlaceAnnotation alloc] initWithCoordinate:newCoord andID:i];
annotation.mTitle = annData.title;
annotation.mSubtitle = annData.subtitle;
annotation.indexID = i;
//annotation.indexID = [[i]intValue];
[mapView addAnnotation:annotation];
[annotation release];
}
}
- (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.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation
{
MKPinAnnotationView *pinAnnotation = nil;
if(annotation != mV.userLocation)
{
static NSString *defaultPinID = #"myPin";
pinAnnotation = (MKPinAnnotationView *)[mV dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinAnnotation == nil )
pinAnnotation = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID] autorelease];
pinAnnotation.canShowCallout = YES;
//instatiate a detail-disclosure button and set it to appear on right side of annotation
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
pinAnnotation.rightCalloutAccessoryView = infoButton;
//infoButton.tag =
//[infoButton addTarget:self action:#selector(onMapVenueSelect) forControlEvents:UIControlEventTouchUpInside];
//defaultPinID.rightCalloutAccessoryView = infoButton;
//infoButton.tag = [event indexOfObject:tmpVenueData];
// [defaultPinID release];
}
return pinAnnotation;
[pinAnnotation release];
}
thanks
Consider using the MKAnnotation protocol and storing whatever you need ID or data wise your object.
A starting point header might go something like this:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#interface YourFancyAnnotationClass : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
NSNumber *companyID;
}
#property(nonatomic, assign) CLLocationCoordinate2D coordinate;
#property(nonatomic, copy) NSString *title;
#property(nonatomic, copy) NSString *subtitle;
#property(nonatomic, copy) NSNumber *companyID;
#end
Then in your delegate do something like this...
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
NSLog(#"calloutAccessoryControlTapped:");
YourFancyAnnotationClass *tappedSite = (SiteAnnotation *)[view annotation];
NSNumber *companyIDThatWasClickedExample = [tappedSite companyID];
etc...

tableView:didSelectRowAtIndexPath: calls TTNavigator openURLAction:applyAnimated: — UITabBar and navigationItem disappear

I have an existing iphone project with a UITabBar. Now I need styled text and in-text links to other ViewControllers in my app. I am trying to integrate TTStyledTextLabel.
I have a FirstViewController:UITabelViewController with this tableView:didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *url;
if ([self.filteredQuestions count]>0) {
url = [NSString stringWithFormat:#"%#%d", #"tt://question/", [[self.filteredQuestions objectAtIndex:indexPath.row] id]];
[[TTNavigator navigator] openURLAction:[[TTURLAction actionWithURLPath: url] applyAnimated:YES]];
} else {
Question * q = [self.questions objectAtIndex:indexPath.row] ;
url = [NSString stringWithFormat:#"%#%d", #"tt://question/", [q.id intValue]];
}
TTDPRINT(#"%#", url);
TTNavigator *navigator = [TTNavigator navigator];
[navigator openURLAction:[[TTURLAction actionWithURLPath: url] applyAnimated:YES]];
}
My mapping looks like this:
TTNavigator* navigator = [TTNavigator navigator];
navigator.window = window;
navigator.supportsShakeToReload = YES;
TTURLMap* map = navigator.URLMap;
[map from:#"*" toViewController:[TTWebController class]];
[map from:#"tt://question/(initWithQID:)" toViewController:[QuestionDetailViewController class]];
and my QuestionDetailViewController:
#interface QuestionDetailViewController : UIViewController <UIScrollViewDelegate , QuestionDetailViewProtocol> {
Question *question;
}
#property(nonatomic,retain) Question *question;
-(id) initWithQID:(NSString *)qid;
-(void) goBack:(id)sender;
#end
When I hit a cell, q QuestionDetailViewController will be called — but the navigationBar wont
#implementation QuestionDetailViewController
#synthesize question;
-(id) initWithQID:(NSString *)qid
{
if (self = [super initWithNibName:#"QuestionDetailViewController" bundle:nil]) {
//;
TTDPRINT(#"%#", qid);
NSManagedObjectContext *managedObjectContext = [(domainAppDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSPredicate *predicate =[NSPredicate predicateWithFormat:#"id == %#", qid];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Question"
inManagedObjectContext:managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
[request setPredicate:predicate];
NSError *error = nil;
NSArray *array = [managedObjectContext executeFetchRequest:request error:&error];
if (error==nil && [array count]>0 ) {
self.question = [array objectAtIndex:0];
} else {
TTDPRINT(#"error: %#", array);
}
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
[TTStyleSheet setGlobalStyleSheet:[[[TextTestStyleSheet alloc] init] autorelease]];
[self.navigationController.navigationBar setTranslucent:YES];
NSArray *includedLinks = [self.question.answer.text vs_extractExternalLinks];
NSMutableDictionary *linksToTT = [[NSMutableDictionary alloc] init];
for (NSArray *a in includedLinks) {
NSString *s = [a objectAtIndex:3];
if ([s hasPrefix:#"/answer/"] || [s hasPrefix:#"http://domain.com/answer/"] || [s hasPrefix:#"http://www.domain.com/answer/"]) {
NSString *ttAdress = #"tt://question/";
NSArray *adressComps = [s pathComponents];
for (NSString *s in adressComps) {
if ([s isEqualToString:#"qid"]) {
ttAdress = [ttAdress stringByAppendingString:[adressComps objectAtIndex:[adressComps indexOfObject:s]+1]];
}
}
[linksToTT setObject:ttAdress forKey:s];
}
}
for (NSString *k in [linksToTT allKeys]) {
self.question.answer.text = [self.question.answer.text stringByReplacingOccurrencesOfString:k withString: [linksToTT objectForKey:k]];
}
TTStyledTextLabel *answerText = [[[TTStyledTextLabel alloc] initWithFrame:CGRectMake(0, 0, 320, 700)] autorelease];
if (![[self.question.answer.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] hasPrefix:#"<div"]) {
self.question.answer.text = [NSString stringWithFormat:#"%<div>%#</div>", self.question.answer.text];
}
NSString * s = [NSString stringWithFormat:#"<div class=\"header\">%#</div>\n%#",self.question.title ,self.question.answer.text];
answerText.text = [TTStyledText textFromXHTML:s lineBreaks:YES URLs:YES];
answerText.contentInset = UIEdgeInsetsMake(20, 15, 20, 15);
[answerText sizeToFit];
[self.navigationController setNavigationBarHidden:NO animated:YES];
[self.view addSubview:answerText];
[(UIScrollView *)self.view setContentSize:answerText.frame.size];
self.view.backgroundColor = [UIColor whiteColor];
[linksToTT release];
}
.......
#end
This works quite nice, as soon as a cell is touched, a QuestionDetailViewController is called and pushed — but the tabBar will disappear, and the navigationItem — I set it like this: self.navigationItem.title =#"back to first screen"; — won't be shown. And it just appears without animation.
But if I press a link inside the TTStyledTextLabel the animation works, the navigationItem will be shown.
How can I make the animation, the navigationItem and the tabBar be shown?
I found a solution:
My QuestionDetailViewController implements the TTNavigatorDelegate.
-(BOOL)navigator:(TTNavigator *)navigator shouldOpenURL:(NSURL *)URL will always return NO, but will call [self.navigationController pushViewController:c animated:YES];
-(BOOL)navigator:(TTNavigator *)navigator shouldOpenURL:(NSURL *)URL {
NSEntityDescription *entity;
NSPredicate *predicate;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
if ([[URL host] isEqualToString:#"question"]) {
entity =[NSEntityDescription entityForName:#"Question" inManagedObjectContext:managedObjectContext];
predicate = [NSPredicate predicateWithFormat:#"id == %#", [[URL path] stringByReplacingOccurrencesOfString:#"/" withString:#""]];
[request setEntity:entity];
[request setPredicate:predicate];
NSError *error =nil;
NSArray *array = [managedObjectContext executeFetchRequest:request error:&error];
if (error==nil && [array count] >0) {
QuestionDetailViewController *c = [[[QuestionDetailViewController alloc] init] autorelease];
c.question = [array objectAtIndex:0];
[self.navigationController pushViewController:c animated:YES];
}
}
[request release];
return NO;
}
In your TableViewController, add:
- (id<UITableViewDelegate>)createDelegate {
return self;
}
Then you can implement your own didSelectRowAtIndexPath and accessoryButtonTappedForRowWithIndexPath methods.