I have two nsmutablearrays
array1: searchedStores = [[NSMutableArray alloc] init];
array2: allStores; ///it holds Stores information and it is also
NSMutableArray
Now if i add objects in "searchedStores" Array
for (int i= 0; i < [allstores count]; i++){
Franchise *store = [allStores objectAtIndex:i];
if ([store.ZipCode hasPrefix:str]) /// where str is searched string
{
[searchedStores addObject:store]; // some stores information will be inserted in "searchedStores" array
}
}
Now if i remove objects from searchedStores array it will also remove objects from "allStores" array
to remove objects i am writing
[searchedStores removeAllObjects];
How can i remove objects only from "searchedStores" array. and "allStores" Array should keep its objects.
IF you are just assigning allstores array with searchedstores array then changes made in searched stores array will be reflected to allstores. You need to allocate new memory to allstores and then add objects from searchedstores array to it upon your logical behavior.
Every array is totally independent. If removing objects from one array effects the other, you don't have two arrays, but only two pointers to the same array. You need to instantiate (alloc/init or mutableCopy) both. Feel free to show your initialization code as well.
Related
I have an array of custom objects which contains a custom object Address with properties street, area, state, country.
I need to get all the the names of the areas from that array so i did some thing like this.
NSMutableArray *areas = [[NSMutableArray alloc]init];
for (Address *item in addresses) {
[areas addObject:item.area];
}
Now areas contain all the names of the area.
Is there any other way to get the all the areas of address items with out looping through the array of addresses (as above), using predicates or some other way.
Well as long as the object is KVC-compliant for the area property then simply:
NSArray *areas = [addresses valueForKey:#"area"];
(If you want areas to be mutable, as per your code, then you'll need to use mutableCopy in the above statement).
See [NSArray valueForKey:]:
Returns an array containing the results of invoking valueForKey: using
key on each of the array's objects.
Also We are using mutableArrayValueForKey: method to get the array of values corresponding to the key
NSMutableArray *areas = [addresses mutableArrayValueForKey:#"name"];
Hi in one of my application,I have an array which contains a group of NSMutableDictionary objects. The dictionary object have three key-value pairs as like below
company
product
quantity
And array having many number of objects. Here now by using different add buttons I am adding these dictionary objects to the array. Even while adding objects to array i am checking whether any duplicate objects are available or not using NSNotFound method. As such below
if([Array indexOfObject:dicObject] == NSNotFound)
{
[Array addObject:dicObject];
}
Here it is working fine in few cases, But it's not working in other cases.I will explain with one example :
For example i have one dicobject in array with following key value pairs
company:XYZ Product:ABC Quantity:2
Now for example I want to add one more dic object with the same above key value pairs. That time obviously it won't add because already same product is available in array.
This is valid condition.
Exceptional Case: For example I want to add one more product with following values
Company:XYZ Product:ABC Quantity:6
At this case this product is adding into the array without any error. But my concern is i don't want to add this into the array again only the quantity have to update, because company and product name both are same so. So can you please show me the way to handle this scenario.
You could use indexOfObjectPassingTest: to know if a similar dictionary is already present in the array.
This may look something like this:
NSMutableArray *arr = // your array
NSDictionary *dicObject = // your object
NSUInteger indexOfDicObject = [arr indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop)
{
return ([obj[#"company"] isEqualToString:dicObject[#"company"]] &&
[obj[#"product"] isEqualToString:dicObject[#"product"]]);
}];
if (indexOfDicObject == NSNotFound)
{
[arr addObject:dicObject];
}
else
{
NSNumber *quantity = arr[indexOfDicObject][#"quantity"];
arr[indexOfDicObject][#"quantity"] = #([quantity intValue] + [dicObject[#"quantity"] intValue]);
}
I made the following assumptions:
the company value is a NSString;
the product value is a NSString;
the quantity value is an integer, stored in a NSNumber.
See also trojanfoe's answer, which is better if you can replace your dictionaries by classes.
I think you need to change tack; first create a custom object to hold your company, product and quantity and ensure you implement the isEqual: and hash methods.
Then simply store your custom objects within an NSMutableSet object, which will ensure that duplicates cannot exist.
Your custom object will now become your principle Model object for the app (i.e. provide the 'M' in MVC, the design pattern upon which Cocoa and Cocoa Touch apps are based) and you will find that it will be reused over and over as the app grows.
How to create an array of non-retained objects in arc? These objects are observers in this array. Currently, I'm creating this array in this way:
_observers = CFBridgingRelease(CFArrayCreateMutable(NULL, 0, NULL));
The problem is the code crashes sometimes when making notifications in this line:
for (NSInteger i = [_observers count] - 1; i >= 0; i--) {
// crash line
id<ListModelObserver> observer = (id<ListModelObserver>)[_observers objectAtIndex:i];
...
I have zombies enabled on, and clearly see observer object classname in debug console. The observer object should be already removed from _observers during dealloc... The only thing that comes to my mind is _observers array somehow retains its objects. Any ideas?
You're releasing the array, not the objects. If you want to have a collection of unsafe unrestrained pointers to objects, then either use a C array or set up a CFArrayRef that doesn't include any call back functions.
I have a controller which has an array holding actors. An actor is a object which will be called by the controller.
The problem: The controller iterates over the actors array and sends each actor an -actionMessage. The actor can create and register another actor with the controller, or remove an actor or even itself from the controller's actors array. It is routed through two methods:
-registerActor:(Actor*)actor;
-unregisterActor:(Actor*)actor;
So while the controller iterates over the actors array, the list of actors can change.
Edit: And any newly added actor MUST go through the loop as well.
What is best practice to deal with this problem? Should I create a copy of the actors array before iterating over it?
Create a copy of your mutable array and iterate over that.
NSArray *loopArray = [NSArray arrayWithArray: yourActorArray];
Or
NSArray *loopArray = [yourActorArray copy];
//in this case remember to release in nonARC environment
This is what I usually do...
NSMutableArray *discardedItems = [NSMutableArray array];
SomeObjectClass *item;
for (item in originalArrayOfItems) {
if ([item shouldBeDiscarded])
[discardedItems addObject:item];
}
[originalArrayOfItems removeObjectsInArray:discardedItems];
hoping this helps.
The standard procedure for enumerating through a mutable array that needs to be altered as you step through it is to make a copy and iterate through that, altering the original. I'm guessing the NSMutableArray of actors is a property belonging to your controller, and that registerActor: and unregisterActor: both alter this array. If you step through a copy you can remove actors from the original property through the methods without altering the copy.
NSMutableArray *actorArrayCopy = [self.actorArray copy];
for (id object in actorArrayCopy){
//do stuff
}
In some cases, you can scrap fast enumeration and use a standard for loop, however, this is risky here. If objects are inserted or removed from the array, the indexes will shift (AFAIK), meaning you may end up skipping elements or going over an element multiple times.
Some people store elements to be altered (such as removed) in a separate array within the fast enumeration and perform all the changes at once once the enumeration is done, but you are using separate methods for adding and removing elements; the elements themselves determine what should happen and notify you. This would make things more complicated, so a copy will probably work best.
You can avoid making a copy of the array by doing this:
for(int i=0; i<[array count]; i++)
{
if(condition)
{
[array removeObjectAtIndex:i];
i --;
continue;
}
}
You should use a set instead of an array. Then you can copy the set, and after the operation is done, take a diff to see whats changed.
I've made a macro called smartFor that allows you to do the same set up as a for-loop fast enumeration but handles modification of array. It takes advantage of a few C and CLANG exploits and is very simple and clean.
Macro:
///Allows for modifying an array during virtual fast enumeration
#define smartFor(__objectDeclaration, __array, __block) {\
int __i = 0;\
while (__i < __array.count) {\
__objectDeclaration = __array[__i];\
NSObject *__object = __array[__i];\
[__block invoke];\
if ([__array indexOfObjectIdenticalTo:__object] != NSNotFound && ((int)[__array indexOfObjectIdenticalTo:__object]) <= __i) {\
__i = ((int)[__array indexOfObjectIdenticalTo:__object])+1;\
}\
}\
}
It automatically handles all of the [basic] wonky things you may do like adding objects (anywhere in the array, at any point during the "fast enumeration"[1]), removing objects, adjusting the index of objects, modifying objects, etc.
Example Usage:
smartFor(NSNumber *aNumber, myArray, ^{
if ([aNumber isEqualToNumber:#(3)]) {
[myArray removeObjectIdenticalTo:aNumber];
}
});
[1]Note: It's not technically fast enumeration on a strict definition/performance basis, obviously, but behaves just like it for all intents and purposes
I have two NSMutableArrays. One array consists of records from the database and the other array consists of records from webservices.
I want to compare each record from the database array to each record in the web services array using a unique key like barcodeID. Also, if the barcodeID key is same then I want to remove the item from the array. It's like I'm updating my database records. If we get the same records from the webservice then I don't want to insert them.
Please help me I'm unable to break the logic for this.
if Product.barcodeID uniquely identifies your objects, then you can use that member to implement -[Product hash] and -[Product isEqual:].
then you can easily use Product in NSSets. NSSet and NSMutableSet contain several methods to combine and remove sets.
The brute force method of doing such comparison is for every record in one array is checked with every record in another. If you find it then stop and discard the object. if you do not find it, then you add it to the array. This of course will have a very high time complexity with a worse case scenario is O(n^2). you could shorten this down by using certain data structures inside your database and web service. Maybe storing them in sorted order or through some algorithm.
You should do some research yourself before asking this question. I shall leave you the option to find a way to optimize your code.
Good luck!
This is kind of the idea of the brute force method. As mentioned above this is incredibly slow compared to alternatives.
- (void)myUpdateFunction
{
NSMutableArray *baseDatabaseArray;
NSMutableArray *baseWebServiceArray;
for (int i = 0; i < baseWebServiceArray.count; i++) {
id value = [[baseWebServiceArray objectAtIndex:i] valueForKey:#"barcodeID"];
NSArray *array = [baseDatabaseArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"barcodeID = %#", value]];
if (array.count > 0)
{
id obj = [array objectAtIndex:0];
[baseDatabaseArray removeObject:obj];
}
[baseDatabaseArray addObject:[baseWebServiceArray objectAtIndex:i]];
}
}
I have been using Magical Record and love it.
You have to be using Core Data for this though. Here is what my update code looks like with Magical Record.
- (void)updateDatabase
{
Class class = NSClassFromString(self.managedObjectClassName);
if ([class MR_countOfEntities] > 0) {
for (NSArray *array in self.totalBatches) {
[class MR_updateFromArray:array];
}
} else {
for (NSArray *array in self.totalBatches) {
[class MR_importFromArray:array];
}
}
[self.totalBatches removeAllObjects];
}
If you have any questions about Core Data feel or if you need me to walk through the algorithms feel free to ask.