I have a mutablearray that is populated from sqlite db in ios. I have gotten the annotations to load and view properly. My question is how can I write a loop that will add annotations with the size of the array. I have tried the following code and get and display the last entry in the array
NSMutableArray *annotations=[[NSMutableArray alloc] init];
CLLocationCoordinate2D theCoordinate5;
MyAnnotation* myAnnotation5=[[MyAnnotation alloc] init];
for (int i = 0; i < _getDBInfo.count; i++) {
dbInfo *entity = [_getDBInfo objectAtIndex:i];
NSNumber *numlat=[[NSNumber alloc] initWithDouble:[entity.Latitude doubleValue]];
NSNumber *numlon=[[NSNumber alloc] initWithDouble:[entity.Longitude doubleValue]];
NSLog(#"%d",[_getDBInfo count]);
la=[numlat doubleValue];
lo=[numlon doubleValue];
theCoordinate5.latitude=la;
theCoordinate5.longitude=lo;
myAnnotation5.coordinate=theCoordinate5;
myAnnotation5.title=[NSString stringWithFormat:#"%#"entity.EntityNo];
myAnnotation5.subtitle=[NSString stringWithFormat:#"%#",entity.EntityName];
[mapView addAnnotation:myAnnotation5];
[annotations addObject:myAnnotation5];
}
I guess my question is how can I create and add to my view annotation objects based on the count in my array?
Any help is much appreciated.
I am new to iOS as well as programming so please be gentle.
You only have one myAnnotation5 object. When you set its coordinate, title, etc., you are setting it for that instance, which you happen to have added to annotations multiple times. Hence every entry in annotations will have the last set of properties you set - since every entry in annotations is actually the same object.
To remedy this, you need to create your myAnnotation5 object anew each iteration of the loop, i.e.
for (int i = 0; i < _getDBInfo.count; i++) {
MyAnnotation* myAnnotation5=[[MyAnnotation alloc] init];
...
myAnnotation5.coordinate=theCoordinate5;
myAnnotation5.title=[NSString stringWithFormat:#"%#", entity.EntityNo];
myAnnotation5.subtitle=[NSString stringWithFormat:#"%#", entity.EntityName];
...
[mapView addAnnotation:myAnnotation5];
}
Two asides:
I hope you are building with ARC, otherwise you are leaking memory left and right.
Since MKMapView has an -annotations property, there is likely little reason for you to keep your own annotations array - just keep a reference to mapView.
Move this line:
MyAnnotation* myAnnotation5=[[MyAnnotation alloc] init];
to inside the for-loop just before setting the properties on myAnnotation5.
The way it is right now, you are creating only one MyAnnotation object and modifying its properties repeatedly.
Related
Im trying to inset data in to the array (temp) but for some reason it saves the same data over an over. I all ready checked the _singleSeismicInfo to verify that it was handling different data(you can see it in the double "/" printData method). So i know the problem is with the MutableArray.
Im new to iOS so if theres something Im not doing right let me know.
NSMutableArray *temp = [[NSMutableArray alloc] init];
[_httpContent getTextFromHTTP];
for (int index = 0; index < 10; index++) {
NSString *line = _httpContent.lines[index];
[_singleSeismicInfo fillSeismicInfo:line];
//[_singleSeismicInfo printData];
[temp addObject:_singleSeismicInfo];
}
You're adding _singleSeismicInfo over and over without ever reassigning a new object to the variable as far as I can see. So it's the same object over and over because that's what you add.
I have a NSMutableArray that i define in the header file as:
#property (strong, nonatomic) NSMutableArray *tempPhotosArray;
Then i allocate as:
_tempPhotosArray = [[NSMutableArray alloc] init];
What i'd like to know is if i then go to replaceObjectAtIndex the program will complain on an out of bounds. I want to keep only a set number of items in that array, so is it possible to do a insert or replace? i.e. if at index 0 it is empty do an insert, if there is an object already replace it?
Thanks
i think i agree with Hani Ibrahim. Since you said you only want to keep a set number of objects in the array. So how many you want?
// add these code when you initialize the array
int aSetNumber = 5;
_tempPhotosArray = [[NSMutableArray alloc] init];
for (int i = 0; i < aSetNumber; i++)
{
[_tempPhotosArray addobject: [NSNull null]];
}
i guess then you can do whatever you want, i don't know what exactly you want to do in this case, but i would check if the object in that position is NSNUll, if so, replace that, if not, i don't know what you want them
//use these code when you trying to insert the real object
if([[_tempPhotoArray objectAtIndex:anIndex] isKindOfClass: [NSNull class]])
{
//replace it here
}
As to why you are getting an error, what everyone else wrote is accurate, but....
The description of what you want doesn't match what an NSArray is. It sounds like you want a list of up to 5 items and never more than 5. It might be that if you try to add a 6th item the "oldest" goes away. Like a "recently opened" file history. You can make this type of functionality with an NSArray, but that's not what it is out of the box.
I would suggest making your own object class. I'm not going to write all the code for you, because this sounds suspiciously like programming homework, but I will point you in the correct direction.
FivePack <-- our class
NSArray *storage; <-- where we house the data
// a public method which lets you add things.
- (void)addItem:(id)item {
int indexOfLastItemInArrayToSave = 4;
if (storage.length < 4)
indexOfLastItemInArrayToSave = length-1;
NSRange range = NSMakeRange(0, indexOfLastItemInArrayToSave);
NSArray *temp = [storage subArrayWithRange:range];
// now create a new array with the first item being "item" that
// was passed in and the rest of the array being the contents of temp.
// Then save that to storage.
}
What you want to do with the data and writing something to get it from your new object is up to you, because I'm not sure how you want to do it.
There are no objects in the array when you initially created it, so there is nothing to replace.
Like this?
if([_tempPhotosArray count] > 0)
//replace object
else
//add object to array
My problem is when I copy an array with objects, it seems that if i change the copied array, the original array changes as well. Below is a simplified version of my code.
I have an array of objects
#interface TimesViewController (){
NSMutableArray *route1;
}
I fill these objects up in my ViewDidLoad method
route1 = [[NSMutableArray alloc] init];
while (sqlite3_step(statement) == SQLITE_ROW) {
StopsOnRoutes *stopOnRoutes = [[StopsOnRoutes alloc] init];
[stopOnRoutes setStart_time:p_time];
[stopOnRoutes setStart_route_id:p_route];
[stopOnRoutes setStart_stop_id:p_stop];
[stopOnRoutes setStop_time:c_time];
[stopOnRoutes setStop_route_id:c_route];
[stopOnRoutes setStop_stop_id:c_stop];
[stopOnRoutes calc];
[route1 addObject:stopOnRoutes];
}
BUT when I try to copy route1 and make a few changes, they change both in route1 and amTimes
NSMutableArray *amTimes = [[NSMutableArray alloc] init];
[amTimes addObjectsFromArray:route1];
for(int i = 0; i<amTimes.count; i++){
[[amTimes objectAtIndex:i] setStop_time:[[amTimes objectAtIndex:i] stop_time]-86400];
[[amTimes objectAtIndex:i] setStart_time:[[amTimes objectAtIndex:i] start_time]-86400];
}
How can I copy route1 to amTimes, so if I change an object in AM times, it won't change in route1.
The way arrays work they simply hold references (pointers) to the objects in the array. Therefore when you add objects, it does not create a new object and point to it, it simply points to that very same object. What you want to do is referred to as a deep copy array, which involves coping each object inside the array.
Which is what happens when you use
- (instancetype)initWithArray:(NSArray *)array copyItems:(BOOL)flag
Each object in the array is send a copyWithZone, you can implement copyWithZone in each of the objects you want to add to your array, and then do
[myArray addObject[myObject copy]];
Or you can also use
[[NSArray alloc] initWithArray:otherArray copyItems:YES] //You need to implement copyWithZone in the items you want to copy.
This will give you the result that you want.
You need to have your StopOnRoutes class implement the NSCopying protocol and the copyWithZone: method. This method needs to create a copy of self.
Then you can do this:
NSMutableArray *amTimes = [[NSMutableArray alloc] init];
for (StopOnRoutes *obj in route1) {
[amTimes addObject:[obj copy]];
}
Container objects don't contain copies of the objects that are added to them, they contain pointers to the objects. If you add the same object to 2 arrays, it is a member of both arrays.
If you want to create an array of copies, you need to do several things:
You need to implement the NSCopying protocol for the objects in your array so you can copy them.
Then you'd need to create a new mutable array with room for the same number of elements as the first array, loop through the first array, copy each item, and add it to the second array.
If your array contains only standard system objects that support NSCopying then your work is simpler. If your array contains different kinds of custom objects or complex custom objects then you might have more work to do.
Try using setArray: i.e.[amTimes setArray:route1];
I'm using an NSMutableArray to populate cells in my tableview. The problem is, when I try adding an object to my array, it replaces all the objects with the one that was added so I always only have 1 object in my array. Because of this, my tableview always has one cell that is just overwritten whenever the below method is called. Am I missing something?
_selectedThingArray = [[NSMutableArray alloc] init];
_currentThing = newThing;
//Note: newThing is the object being passed when this method is called.
//It is the new data that will should passed into the cell.
[_selectedThingArray addObject:_currentThing];
NSLog(#"%#", newThing);
NSLog(#"array: %#", _selectedThingArray);
[self.tableView reloadData];
Is this line:
_selectedThingArray = [[NSMutableArray alloc] init];
executed every time you "try adding an object"? If yes, then this is your problem. Instead of adding an object to an existing array, you replace it with a brand new array and add object to this new array.
You need to either create the array at some point before you “try adding an object”, or create the array in the same place you're doing it now, but only when you have not already created one.
Add this if condition before allocation:
if(!_selectedThingArray)
_selectedThingArray = [[NSMutableArray alloc] init];
Instead of this only:
_selectedThingArray = [[NSMutableArray alloc] init];
Everything will be fixed.
I read through many topic but i don't think i really get them.
I found the following code in one of the topic but I am not sure how to put it. Should i put in viewdidload? or somewhere else?
And I have a large annotation data of 3000 dots. But I dont know how to read a sqlite data (I am using a plist data) Please give me a help.
Thanks in advance.
// create and populate an array containing all potential annotations
NSMutableArray *allPotentialAnnotations = [NSMutableArray array];
for(all potential annotations)
{
MyAnnotation *myannotation = [[MyAnnotation alloc]
initWithCoordinate:...whatever...];
[allPotentialAnnotations addObject:myannotation];
[myannotation release];
}
// set the user's current location as the reference location
[allPotentialAnnotations
makeObjectsPerformSelector:#selector(setReferenceLocation:)
withObject:mapView.userLocation.location];
// sort the array based on distance from the reference location, by
// utilising the getter for 'distanceFromReferenceLocation' defined
// on each annotation (note that the factory method on NSSortDescriptor
// was introduced in iOS 4.0; use an explicit alloc, init, autorelease
// if you're aiming earlier)
NSSortDescriptor *sortDescriptor =
[NSSortDescriptor
sortDescriptorWithKey:#"distanceFromReferenceLocation"
ascending:YES];
[allPotentialAnnotations sortUsingDescriptors:
[NSArray arrayWithObject:sortDescriptor]];
// remove extra annotations if there are more than five
if([allPotentialAnnotations count] > 5)
{
[allPotentialAnnotations
removeObjectsInRange:NSMakeRange(5,
[allPotentialAnnotations count] - 5)];
}
// and, finally, pass on to the MKMapView
[mapView addAnnotations:allPotentialAnnotations];
probably the first thing to do is clustering your data on the map. that means combining several points to one point on the map. the more the user zoomes in the more the clusters will be resolved to single points placed on the map.
there are some recommendations how to do that in this post:
How can I reduce the number of annotations on a map?
the next step is to itterate through your data and check if one point is within the region arround the user location. you can get the GEO position of the visible display area like this:
CLLocationCoordinate2d topLeft, bottomRight;
topLeft = [mapView convertPoint:CGPointMake(0, 0) toCoordinateFromView:mapView];
CGPoint pointBottomRight = CGPointMake(mapView.frame.size.width, mapView.frame.size.height);
bottomRight = [mapView convertPoint:pointBottomRight toCoordinateFromView:mapView];