I am working on one app in which I want a feature to block call. If i am passing static values to addBlockingEntryWithNextSequentialPhoneNumber it's blocking numbers but when i'm passing array in addBlockingEntryWithNextSequentialPhoneNumber it's not blocking numbers. I have logged my array in Appdelegate and it looks fine.
Appdegate Code:
NSArray *sortedArr = [lockedArr sortedArrayUsingSelector:#selector(compare:)];
[DEFAULTS setObject:sortedArr forKey:#"SortedBlockedUsers"];
NSArray<NSNumber *> *blockedPhoneNumbers = [DEFAULTS objectForKey:#"SortedBlockedUsers"];
for (NSNumber *phoneNumber in blockedPhoneNumbers) {
NSLog(#"phoneNumber == %lld", (CXCallDirectoryPhoneNumber)[phoneNumber unsignedLongLongValue]);
}
output is: phoneNumber == 918849494978 phoneNumber == 919142142124
HandlerClass code:
NSArray<NSNumber *> *blockedPhoneNumbers = [[NSUserDefaults standardUserDefaults] objectForKey:#"SortedBlockedUsers"];
//NSArray<NSNumber *> *blockedPhoneNumbers = #[ #918823514521, #919586112211 ];
for (NSNumber *phoneNumber in blockedPhoneNumbers)
{
[context addBlockingEntryWithNextSequentialPhoneNumber:(CXCallDirectoryPhoneNumber)[phoneNumber unsignedLongLongValue]];
}
Finally after debugging my extension class I found that problem is assigning value to array from NSUserDefaults. We must have to save and retrieve value using NSUserDefaults SuiteName to interact with Extension class.
Related
Hi together I have a Problem:
I read out the actual Values of the Playing media song, and add it to a dictionary.
And then into an Array. If I add a new entry pressing the Button again, all Values of all entrys changing to the same.
Do you have an Idea why?
Here my Code:
- (IBAction)ActionButtonLU:(id)sender
{
MPMediaItem *currentItem = [musicPlayer nowPlayingItem];
NSString *titleString = [currentItem valueForProperty:MPMediaItemPropertyTitle];
NSString *artistString = [currentItem valueForProperty:MPMediaItemPropertyArtist];
NSString *albumString = [currentItem valueForProperty:MPMediaItemPropertyAlbumTitle];
if (titleString == nil) {
titleString = #"";
}
if (artistString == nil) {
artistString = #"";
}
` `if (albumString == nil) {
albumString = #"";
}
[_dictCat1 setObject:titleString forKey:#"Titel"];
[_dictCat1 setObject:artistString forKey:#"Artist"];
[_dictCat1 setObject:albumString forKey:#"Album"];
[_countCat1 addObject:_dictCat1];
[musicPlayer skipToNextItem];
}
You are modifying the same dictionary, _dictCat1, in every call. You need to create a dictionary locally and add that to _countCat1.
[_countCat1 addObject:#{ #"Title": titleString,
#"Artist": artistString,
#"Album": albumString }];
When you add an object to a collection (NSArray, NSDictionary, NSSet etc, including mutable counterparts), the collection doesn't copy it. With [_countCat1 addObject:_dictCat1]; you keep adding the same object to _countCat1 over and over. You need to create new NSDictionary and add that to _countCat1 collection.
I have a NSlog that is giving odd output in the debugger. How do I get it to show the proper value?
NSError *error = nil;
NSArray *data;
[self setStatus:#"Syncing data..."];
self.userInfo = [self.cloud Authenticate:[self serialNumber]];
if ( self.deviceInfo )
{
data = [self.device GetData:&error];
if ( !data )
{
[self displayErrorMessage:error];
data = [NSMutableArray array];
}
//data received from device: Log point
NSLog(#"data received from device: %#",data);
Debuger output
"<DataPoint: 0x1001f81b0>",
"<DataPoint: 0x10012f5f0>",
"<DataPoint: 0x1001f7780>",
"<DataPoint: 0x1001f8780>",
This is the default string returned by NSObject's description method, which just prints the pointer value. If you want to see the proper data printed, override description in your DataPoint class:
- (NSString*) description
{
// Example:
return [NSString stringWithFormat: #"ivar1=%# , ivar2=%#",ivar1, ivar2];
}
As you stored an object of DataPoint in the array, correct output is shown.
If you want to see full value for each of them, then you need to use
for(DataPoint *dp in data){
NSLog(#"%#",dp.property);//property should be your property name of DataPoint class.
}
+1 for #Ramy's good suggestion to override description, I suggest extending, rather than replacing, like this:
- (NSString *)description {
return [NSString stringWithFormat: #"%#: ivar1=%#, ivar2=%#",
[super description], self.ivar1, self.ivar2];
}
The inherited behavior that answers the class and the %p pointer is very useful, too.
I have set up my simple Xcode project with a table that is binded to an array controller. It works fine if the array controller is full of entities with a string attribute. However I want to change the attribute to a BOOL and have the table show the string "true" or "false" based on the BOOL.
I have overrided the following two methods from NSFormatter:
-(NSString*) stringForObjectValue:(id)object {
//what is the object?
NSLog(#"object is: %#", object);
if(![object isKindOfClass: [ NSString class ] ] ) {
return nil;
}
//i'm tired....just output hello in the table!!
NSString *returnStr = [[NSString alloc] initWithFormat:#"hello"];
return returnStr;
}
-(BOOL)getObjectValue: (id*)object forString:string errorDescription:(NSString**)error {
if( object ) {
return YES;
}
return NO;
}
So the table gets populated with "hello" if the attribute is a string however if I switch it to a boolean, then the table gets populated with lots of blank spaces.
I don't know if this helps but on the line where I'm outputting the object, it outputs __NSCFString if the attribute is a string and "Text Cell" if I switch the attribute to a boolean. This is something else I don't understand.
Ok, it's not 100% clear what you're trying to do from the code, but first things first - BOOL is not an object, it's basically 0 or 1, so to place BOOL values into an array, you're probably best off using NSNumber:
NSNumber *boolValue = [NSNumber numberWithBool:YES];
and placing these into your array. Now you want to change your method:
-(NSString*) stringForObjectValue:(id)object {
NSNumber *number = (NSNumber *)object;
if ([number boolValue] == YES)
return #"true";
else
return #"false";
}
There's a few things here - for example, you want to avoid passing around id references if you can (if you know all your objects in the NSArray are NSNumber, you shouldn't need to).
I have the following test case in my iOS application :
-(void) testTwoDefaultUsersExist
{
NSString * expected;
NSString * actual;
expected = #"John Smith";
actual = [[[userService getAllUsers]objectAtIndex:0] fullName];
STAssertEqualObjects(expected, actual, #"Not equal");
expected = #"Dave Brown";
actual = [[[userService getAllUsers]objectAtIndex:1] fullName];
STAssertEqualObjects(expected, actual, #"Not equal");
}
The above just checks that my call to [userService getAllUsers] returns 2 User objects, one with a name of John Smith, the other with Dave Brown. This appears to work fine for this scenario, but I have other cases where that ordering may change, so John may be placed in index 1 rather than 0
Question : How can I assert that the NSMutableArray, being returned from the call to [userService getAllUsers] contains those 2 objects, regardless of ordering?
Can you not simply use the NSArray method -containsObject:? An NSMutableArray is still an NSArray, so you can do:
NSArray * expected = [NSArray arrayWithObjects:#"John Smith", #"Dave Brown", nil];
NSArray * actual = [[userService getAllUsers] valueForKey:#"fullName"];
for(NSString * name in expected) {
STAssertTrue([actual containsObject:name], #"Missing name");
}
Note the (ab)use of -valueForKey: to transform an array of user objects into an array of NSString objects, making the -containsObject: call simpler. This will only work if your user object is key-value coding compliant for the fullName property.
NSMutableArray always contains the elements as you insert them to the array
You can iterate over the elements that you insert and test if they're at the NSArray using:
- (NSUInteger)indexOfObject:(id)anObject
If the object is not found it returns NSNotFound, that can be used with the Unit Test Framework that you choice
Greetings
Assert on equality like this
NSAssert1([userService getAllUsers].count == 2, #"SomeDescription", nil);
If you want to search an array for the existence of some strings, use the following function
- (BOOL) containsAllNames:(NSArray*)arrToSearch namesToSearch:(NSArray*)arr
{
BOOL containsAll = YES;
for (NSString *name in arr) {
BOOL containsCurrent = NO;
for (NSString *nameToSearch in arrToSearch) {
if ([name isEqualToString:nameToSearch]) {
containsCurrent = YES;
break;
}
}
if (!containsCurrent) {
containsAll = NO;
}
}
return containsAll;
}
Call it like
NSArray *toSearch = [NSArray arrayWithObjects:#"John Smith", #"Dave Brown", nil];
[self containsAllNames:YourArray namesToSearch:toSearch];
I would like to pass a NSMutableArray by reference so that it can be altered by another method. What would be the correct syntax for this?
Thanks,
Objective-C objects are always passed by reference (using pointers) - you can't pass them by value.
I.e. the following is fine:
- (void)mutateArray:(NSMutableArray*)array {
// alter array ...
}
... and can be e.g. invoked like this:
NSMutableArray *array = ...;
[self mutateArray:array];
There is also the possibility of passing a pointer by reference:
- (void)newArray:(NSMutableArray **)array;
In that case array is used as an out-parameter - you pass a reference to a pointer to receive an instance:
- (void)newArray:(NSMutableArray **)array {
*array = [[NSMutableArray alloc] init];
}
... which could be called like so:
NSMutableArray *array = nil;
[self newArray:&array];
Using out-parameters is usually only seen if the return-value is already used and additional information has to be returned. An example would be error-information as dreamlax noted.
In addition to Georg Fritzche's answer, it may be worth noting that some methods expect to be given the address of an object pointer. For example:
NSError *anError; // points to garbage now
NSStringEncoding enc;
NSString *aString = [NSString stringWithContentsOfFile:#"/some/file.txt"
usedEncoding:&enc
error:&anError];
if (aString == nil)
{
// anError now points to an initialised NSError object.
}
It gets tricky because some documented methods require you to release objects obtained in this manner, and some don't (for an example of one that does require explicit releasing, see NSPropertyListSerialization).
As Georg Fritzsche said NSMutableArray passed be reference automatically, but not the NSArray. The best option is too look at the code bellow:
void mutateImmutableArray(NSArray *array);
void mutateMutableArray(NSMutableArray *array);
void mutateImmutableArrayByRef(NSArray **array);
void mutateMutableArrayByRef(NSMutableArray **array);
int main(int argc, const char * argv[]) {
#autoreleasepool {
//Change immutable array in method that expects immutable array
NSArray *immutable = #[#1,#2,#3];
mutateImmutableArray(immutable);
NSLog(#"After 1: %#",immutable); // 1,2,3
//Change mutable array in method that expects immutable array
NSMutableArray *mutable = [#[#1,#2,#3]mutableCopy];
mutateImmutableArray(mutable);
NSLog(#"After 2: %#",mutable); //1,2,3
//Change mutable array in method that expects mutable array
mutable = [#[#1,#2,#3]mutableCopy];
mutateMutableArray(mutable);
NSLog(#"After 3: %#",mutable); //1,2,3, Four
//Change immutable array in method that expects immutable array by reference
immutable = #[#1,#2,#3];
mutateImmutableArrayByRef(&immutable);
NSLog(#"After 4: %#",immutable); //4,5,6
//Change mutable array in method that expects mutable array by reference
mutable = [#[#1,#2,#3]mutableCopy];
mutateMutableArrayByRef(&mutable);
NSLog(#"After 5: %#",mutable); //1,2,3, Four
}
return 0;
}
void mutateImmutableArray(NSArray *array)
{
array = #[#4,#5,#6];
}
void mutateImmutableArrayByRef(NSArray **array)
{
*array = #[#4,#5,#6];
}
void mutateMutableArray(NSMutableArray *array)
{
[array addObject:#"Four"];
}
void mutateMutableArrayByRef(NSMutableArray **array)
{
[*array addObject:#"Four"];
}