Getting a char out of NSarray in Objective-C - ios

I am trying to get a char out of an NSArray by generating a random number. Here is my code
#interface ClassName : NSObject
#property (nonatomic) char letter;
-(id) init;
-(char) changeLetter;
#end
Implementation File:
#import "ClassName.h"
#interface ClassName()
#property (strong, nonatomic) NSArray *alphabet;
#end
#implementation ClassName
-(id) init {
[self alphabet];
return self;
}
-(NSArray *) alphabet
{
if (!_alphabet) _alphabet =
#[#'A', #'B',#'C', #'D',#'E', #'F',
#'G', #'H',#'I', #'J',#'K', #'L',
#'M', #'N',#'O', #'P',#'Q', #'R',
#'S', #'T',#'U', #'V',#'W', #'X',
#'Y', #'Z'];
return _alphabet;
}
-(char) changeLetter
{
//Picks a number between 0-26
int nextLetter = arc4random_uniform(26);
//Changes the value of the bubble
[self setValue: nextLetter];
return [self.alphabet objectAtIndex:nextLetter];
}
#end
The problem I am running into is the return statement coming from the changeLetter. It is telling me "Incompatible pointer to integer conversion returning 'id' from a function with result type 'char'
I have no idea what the problem is. I am new to Objective-C and am already getting very frustrated it already. It seems so hard and complicated compared to Java.
Can someone tell me what I am doing wrong?
Any help is greatly appreciated.

Coming from Java you might be confused as Java supports autoboxing and autounboxing.
In both Java & Objective-C you cannot store non-object types, such as integers and characters, directly in collections, such as arrays. Instead such values are stored as objects which wrap (or box) the basic value.
In Objective-C the common wrapper is NSNumber which is capable of storing integers, floating point numbers, characters and booleans. There is also an NSValue wrapper for storing other basic values.
Java will wrap a basic value as an object, and unwrap an object to produce the basic value, according to the context automatically. In Objective-C you must do this yourself.
Your expression: #'A' et al takes the character literal, 'A', and wraps it as an NSNumber. In Java the equivalent of the # would be inserted automatically.
So your array _alphabet contains instances of NSNumber. When you access an element of the array using:
[self.alphabet objectAtIndex:nextLetter]
the NSNumber instance in the array is returned, you still need to unwrap it to obtain the character and you do this with the charValue method:
[[self.alphabet objectAtIndex:nextLetter] charValue];
Again Java does the equivalent automatically for you.
Note: for the actual task you are doing there are better ways to return a random capital letter, in your code you could even just use 'A' + nextLetter (remember in C characters are just integers...).
HTH

Related

If this is the right way to use a customised string property in Objective C, why can’t I extract the correct numeric value?

I am revising an early project where I use tags to identify 1-of-5, 1-of-16 or 1-of-10 UIButtons. I want to replace the tags with a customised property based on my understanding of this answer.
The property called myInfo consists of a string followed by an integer. This may well be a tag by another name but it makes a message source uniquely identifiable in a way that a simple integer tag does not, clearing magic numbers from my code and, hopefully, improving the documentation.
The property is created using a category
UIView+CustomProperties.m
#import "UIView+CustomProperties.h"
#implementation UIView (MyInfo)
-(void)setMyInfo:(id)info
{
objc_setAssociatedObject(self, "_myInfo", info, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(id)myInfo
{
return objc_getAssociatedObject(self, "_myInfo") ;
}
#end
And myInfo works when I import objc/runtime.h
UIView+CustomProperties.
#import <objc/runtime.h>
#interface UIView (MyInfo)
#property ( nonatomic, strong ) id myInfo;
#end
I call the category from the method (below) in the UIView where I create several sets of buttons.
// define type and number of 5, 16 or 10 buttons
switch (buttonCount) {
case 5:
roundButton.myInfo = [NSString stringWithFormat:#"transpose index %i", i ];
break;
case 16:
roundButton.myInfo = [NSString stringWithFormat:#"player index %i", i ];
break;
case 10:
roundButton.myInfo = [NSString stringWithFormat:#"note index %i", i ];
break;
default:
roundButton.myInfo = #“orphan button“;
break;
}
To identify a message source I have tried to strip away all non-numeric characters from myInfo using this method. However a problem appears in my selector method forButtons as I attempt to remove non-numeric characters
- (void)fromButtons:(UIButton*)button {
NSLog(#"Button %ld tapped", (long int)[button tag]);
NSLog(#"first, %#", button.myInfo);
NSString *newString = [[button.myInfo componentsSeparatedByCharactersInSet:
[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]
componentsJoinedByString:#""];
NSLog(#"then, %#", newString);
NSLog(#"and %li", (long int)newString);
When I build and run and press button 1, the NSLog statements above produce the following log
2017-05-25 18:27:33.147 SatGam3[930:607301] Button 1 tapped
2017-05-25 18:27:33.147 SatGam3[930:607301] first, transpose index 1
2017-05-25 18:27:33.148 SatGam3[930:607301] then, 1
2017-05-25 18:27:33.148 SatGam3[930:607301] and 2070247168
Note that the long int value for the original tag is correct i.e. 1 whereas the long int recovered from the customised property is 2070247168.
Q.1 Firstly, is this approach correct ?
Q.2 If so, can someone please explain why am I extracting a 9-digit numeric value from myInfo ?
First, a problem that has nothing to do with your problem: Your use of "_myInfo" as the key here is slightly dangerous. In practice you're going to get away with it, but it relies on a compiler optimization that isn't promised. You're betting that the compiler (and possibly the linker) will ensure that all copies of the same constant string refer to the same memory location in the binary. That happens to be true, but it's not part of the language. Use a selector instead.
But that's not your problem. Your problem is this:
NSLog(#"and %li", (long int)newString);
newString is (unsurprisingly) an NSString*. So this points the address of that string. If you want to convert this into a number, you'll want to call -intValue on it.
That said, I wouldn't encode this data as a string. Encode it as a data object:
#interface ButtonInfo
#property (copy) NSString *name;
#property (assign) NSInteger index;
#end
(or name could be an enum if there are fixed set of them)
If you want to make this easier to read, add a -description method. Use the type system; it's there to help you. Don't try to encode a complicated type into a string.
Use below line of code :
NSLog(#"and %li", [newString intValue]);
Your approach is correct.

C-Style 2D Array as ivar

In C, we could do the following to create a 2D array:
int intArray[10][10];
In C99, we could create a VLA:
size_t col = 10;
size_t row = 10;
int array[row][col];
Within a method in Objective-C, I can create a 2D array that hold ids as follows:
id genObjectArray[10][10];
Is it possible to create an 2d array ivar in Objective-C?
The following is what I have tried:
#interface myClass ()
{
id objArray[][];
//This doesn't work, unless I specific size.
//I want to do this, so that I could specific the size later during
//runtime
}
In C, I could do the following and allocate space for a 2D array later within a block scope:
int **array;
int *elements;
I can do the same within Objective-C, too, but the problem arises when I use id or other object types; other words, the following is not valid:
id **array;
id *elements;
Thus, my question is, is it possible to declare a C-style 2D array as ivar that holds ids?
I understand that we could achieve that using normal NS(Mutable)Array; but this just serves for educational purposes.
You can't do this. For a C99 VLA, the space required for the array is allocated at the point the array is declared. For an ivar, the analogous time to do that would be when the object was allocated and initialized, but there's no support in Objective C to do that. You'd need to have a stronger definition of what an object constructor can do (more like Java's constructors than Objective C's initializers).
The closest you can get would be something like this:
#interface myClass () {
id * objArray;
}
-(instancetype)initWithRow:(size_t)row col:(size_t)col {
self = [super init];
if (self) {
objArray = calloc(row * col * sizeof(id));
}
return self;
}
-(void)dealloc {
free(objArray);
}
In that case, you're declaring the ivar as a pointer and managing the storage yourself (and the stride, for a multi-dimensional array).
Obviously, NSArray is better in all possible ways.

How are colons used with ivars?

I'm doing some code refactoring and I've come across some ivars syntax that I haven't seen before. The code looks like
#interface Object : NSObject {
#private BOOL aBool:1;
}
#end
My question is, what does the :1 do?
This syntax has the same meaning for an ivar as it does inside a struct; you're declaring a bitfield of the specified size.
This likely doesn't have any effect on the actual size of the class in this case -- I don't think you can allocate less than a byte -- but the compiler will warn you if you try to put a value into the variable that's too large for the bitfield size you indicated:
#interface BittyBoop : NSObject
{
unsigned char bit:1;
unsigned char bits:4;
}
#end
#implementation BittyBoop
- (void)doThatThingIDo
{
bit = 2; // Implicit truncation from 'int' to bitfield changes value from 2 to 0
bits = 2; // no warning
}
#end

After updating to Xcode 6 many incompatible conversion assignment warnings / errors appeared

After updating to Xcode 6 many incompatible conversion assignment warnings / errors started to appeared
In the .h file:
#property (nonatomic) BOOL *done;
In the .m file:
#synthesize done;
- (id)init
{
if (self = [super init])
{
self.done = FALSE;
}
return self;
}
- (void) crashed {
self.done = TRUE; #this line gives an incompatible type conversion warning
}
Lots of these warnings appeared after the upgrade. Does anyone share similar problem?
This is not a localized problem, the issue spread across the entire project.
I thought some of my foundation was wrong, or is it ?
Not all variables in Objective C have to be declared with the * character as some newcomers to the language think. It is C legacy to show that the variable is a pointer to an object. Some basic types like int and BOOL are too simple to require the overhead of storing them in an object, so C-style primitive types are used. From the docs:
Scalar types are used in situations where you just don’t need the
benefits (or associated overheads) of using an object to
represent a value. While strings of characters are usually represented
as instances of the NSString class, numeric values are often stored in
scalar local variables or properties.
BOOL is a primitive data type in Objective C and is not supposed to be a pointer. The warnings are correct. Declare the variable like this:
#property (nonatomic) BOOL done;
Note the lack of the * character next to the variable name. Other primitive types like int or float also should be declared in a similar fashion.
Some other things about your code. The correct Objective C convention for BOOL values is YES instead of TRUE and NO instead of FALSE, so you should stick to it. Also, since Xcode 4.4, you don't need #synthesize outside of a few special cases described here. As pointed out in the comments, it's also better to use instancetype instead of id in your case as described in the docs.
I'm pretty sure you want to do it this way:
Header file
#property (nonatomic) BOOL done; // Note: NOT a pointer
Implementation file
- (instancetype)init {
if (self = [super init]) {
self.done = NO;
}
return self;
}
- (void)crashed {
self.done = YES;
}

I need to build a HashMap like, Map<Set, Set>. Is it possible?

My usecase here is, I need to search for a string within a set of strings(say synonyms). If I find the relevant search-word within the set of strings, then I will display the set of values associated with that set of strings. I am currently thinking of implementing it as a Map, but not sure, if that's even possible.
I am confused about the best data-structure that can be used in this scenario?
Thanks for the help.
EDIT
Replaced Array with Set as it made more sense
Scenario:
Set-1 = {jug,jar,bottle,cup}
Set-2 = {"Store water", "Store Juice", "Store Coffee"}
For any input I receive from either jug,jar,bottle,cup, I should return the properties associated with it from Set-2. In simple words, I need to return whole of Set-2 when any word from Set-1 matches. Hopefully, this will make my question clear.
you can subclass NSObject for that kind of behaviour.
#interface Synonyms : NSObject
#property NSArray *strings;
#property NSArray *values;
-(NSArray *)searchForWord:(NSString *)searchWord;
#end
#implementation Synonyms
-(NSArray *)searchForWord:(NSString *)searchWord{
BOOL found=NO;
//add code to search for that search term in strings array
if(found)
return self.values;
else
return nil;
}
#end
so, first create all these synonyms instances and store them in NSArray.
Assign strings and values array to each instance.
When user enters search-word, call searchForWord function for each element of array.
If found ,it returns not nil object.else no synonym.
PART 2:
If you are looking for below kind of behaviour, example below
Dictionary myDic;
myDic.Add("car", "automobile");
myDic.Add("car", "autovehicle");
myDic.Add("car", "vehicle");
myDic.Add("bike", "vehicle");
myDic.ListOSyns("car") // should return {"automobile","autovehicle","vehicle" ± "car"}
// but "bike" should NOT be among the words returned
Then you can use NSDictionary,
NSDictionary *dictionary =#{#"car":#[#"automobile",#"autovehicle",#"vehicle"],#"bike":#[#"vehicle"]};
NSArray *values =[dictionary objectForKey:#"search-term"];
if(values==nil)
//no result
else
return values;

Resources