Convert int to *NSInteger - ios

When using this
NSInteger *myInteger = 45 ;
I get the warning message Incompatible Integer to pointer conversion sending 'NSInteger' (aka 'int') to parameter of type 'NSInteger *' (aka 'int *')
I have read another posts with same warning but did not find proper solution.

NSInteger is not a subclass of NSObject as it might seem, it's a primitive type. Change your code to:
NSInteger a = 45 ;
And (of course) do not name your variable int

You should use different name then int because it is a name for a special primitive type integer. Like that you cannot name a variable with names like for, while, void... Just use another name(and you should name it to understand what it holds) like:
NSInteger myFirstInteger = 45;
Note: In your future projects, please name your variables with a meaningful name ,so that you can create a meaningful piece of code which is easy to understand and improve.

Related

Why Some Variables are Declared with an * Asterisk in Objective-C

I am just starting to learn Objective-C. I am confused to see that some types of variables are sometimes declared with an * asterisk, others are not. For example these are delcared with a *:
#property NSString *firstName;
NSString * mainString = #"Hello World!";
NSNumber *longNumber = #42l;
NSArray *unsortedStrings = #[#"gammaString", #"alphaString", #"betaString"];
And these are not:
int someInteger = 42;
NSInteger anInteger = 64;
id firstObject = #"someString";
NSRange substringRange = [mainString rangeOfString:#"long"];
I found this explanation from Apple's documentation: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithObjects/WorkingwithObjects.html#//apple_ref/doc/uid/TP40011210-CH4-SW1
Both these properties are for Objective-C objects, so they use an asterisk to indicate that they are C pointers.
But this explanation is too general and vague for me to understand the concept. I know type * means it is a pointer type, and this type stores pointers of that type. But why some types are declared with *, others are not?
The int type is not object. It is a C language “primitive data type”. You generally interact with primitive C data types directly. E.g.,
int i = 0; // it’s now `0`
i = 42; // it’s now `42`
The NSInteger is just an alias for another primitive data type, long. The NSRange is a struct (thus, also not an object), so the same rule applies. So, for basic interaction with these primitive data types, no * pointer reference is generally needed. (There actually are times you also deal with pointers to primitive data types, but that is beyond the scope of this question.)
But NSString, NSNumber, and NSArray, however, are objects, so you must use pointers when declaring them.
Note, you've included id in the latter list where * is not used:
id firstObject = #"foo";
Be very careful. This actually is a bit misleading, because firstObject actually is a pointer to the #"someString", a NSString object. The id is an exception to the way we generally declare pointers with * and is discussed in Objective-C is a Dynamic Language), “The id type defines a generic object pointer.”
It’s analogous to declaring a NSString pointer, but “you lose compile-time information about the object”. Compare the id pointer to the NSString * to the following syntax:
NSString *secondObject = #"bar";
This latter secondObject is NSString * pointer, but because we explicitly declared it as a NSString * pointer, the compiler knows that you are dealing with a string (thus the compiler can perform greater validation regarding your subsequent use of that pointer). With id, you do not enjoy this compile-time validation.
For example, here are two invalid attempts to call removeObject method on two NSString objects. NSString has no such method. The NSString * reference provides useful compile-time error message that id does not afford us:
Now, if you used the id type and tried to run that code, it would crash when it attempted to call removeObject on firstObject. But, where possible, it is much better to have the compiler tell us about the error during compile-time, rather than at run-time.
So the id pattern should be used sparingly, only when you really need Objective-C’s dynamic type behaviors.

what is the difference between "variable:Type" and "variable as Type" swift

What is the difference between:
let variable:Double = 23
and "as Type"?
let variable = 23 as Double
let variable:Double = 23
Declaring variable in this way is called Type Annotation in which we are telling complier explicitly that variable is type of Double instead of compiler referring to type of assigned value.
let variable = 23 as Double
This is called type casting .As per definition in Swift,
Type casting in Swift is implemented with the is and as operators.
These two operators provide a simple and expressive way to check the
type of a value or cast a value to a different type.
So these are not different in terms of functionality. Using first way, we are adding redundant token for declaring a constant as type inference would detect type automatically by value.
By Second way, we are forcing a constant to have a kind of value which would be useful in case of superClass/Subclass type casting.

int not returning same value from NSString

I have saved value in Singletone as NSString. When I want to convert to int, value is some random number. For example, I am calling NSString *numberCoupons = [Manager sharedInstance].userProfile.numberOfCoupons, po numberCoupons returning normal value: 40.
But problem is in next line, when I want to convert string to value: int coupons = (int)numberCoupons; It is returning some random number, etc. 421414.
What could be the problem?
try int coupons = [numberCoupons integerValue];
numerofCoupons is obviously an NSNumber object which is used to store numbers within Objective-C collection classes (NSArray, NSDictionary, etc) as only objects can be stored in them.
To get the wrapped value out of the object use:
NSInteger coupons = [numberOfCoupons integerValue]
I would recommend redeclaring numberOfCoupons as NSInteger, and not NSNumber, as NSNumber objects are difficult and expensive to manipulate compared to the primitive types they wrap.
If the value needs to go into a collection class then wrap it in an NSNumber object when adding it and unwrap it when removing it.
When you write (int)numberOfCoupons you are asking that the value in the variable numberOfCoupons be cast to the type int.
Now the value in a variable of type NSString * is a reference to an object, that is a memory address. When (Objective-)C casts a reference to an integer type you get back the memory address. This is the “random” value you are seeing.
What you need to do is send a message to the object referenced by the value in your variable requesting that it return an integer value equivalent to itself. NSString has a method intValue for this, so [numberOfCoupons intValue] will do what you wish.
There is a whole family of xValue methods to obtain various integer and floating-point values of different precision/size.
Note: if you have a reference to an NSNumber, rather than an NSString, then exactly the same code will work.
Note 2: if you do have an NSNumber then the cast expression you first tried may return a value which has a completely different magnitude than you might expect for a memory address. This is because some integer values are represented by special tagged addresses which don't actually reference a real object. This is an optimisation you normally would not notice, except when you accidentally cast the reference value to an integer...
HTH

cannot be applied to operands of type 'UITextField' and 'Int'

I am trying to populate a Label with a text field input * 365
I keep getting the message:
Binary operator '*' cannot be applied to operands of type 'UITextField' and 'Int'
var hours = (hoursTextField.text as NSString).doubleValue
var hoursInAYear = hoursTextField * 365
Your first line is calculating the doubleValue of what's entered into the text field, but you're not using that hours variable. Perhaps you want:
var hoursInAYear = hours * 365
The warning you are getting is telling you that you're trying to use the * operator between a variable whose type is UITextField and another variable whose type is Int (this is what your 365 literal is interpreted as).
This warning will come up any time we try to use an operator between two types for which the operator does not have an overload. It is particularly common when one of our operand's types is implicitly determined because we're using a literal somewhere. To resolve the issue, we must double check our instantiation of our operands and be sure they're of types for which our operator has an overload.
If they are not, then we should either change how we create these variables so they have the right type, or find some way of converting them when we use them with the operator.
When we change our mistaken variable from the text field to the double we just calculated, Swift is able to calculate this correctly. Despite previously claiming that 365 was an Int, being a literal, it can be interpreted as several different types, one of which includes Double.
When we attempt to use the * between a variable of type Double and a literal number, the literal number will be correctly converted to a Double, and we'll use the overload of the * operator which accepts two doubles (and returns a double).
You're trying to multiply hoursTextField by 365. Did you mean to write:
var hours = (hoursTextField.text as NSString).doubleValue
var hoursInAYear = hours * 365 // hours, not hoursTextField.
I think it is basically just a typo or copy-paste-mistake of yours since you already calculate the hours variable correctly and dont use it afterwards. Simply change your second line to
var hoursInAYear = hours * 365

Type casting, why is it so verbose? Or am I doing something wrong?

I have a NSDecimalNumber and an NSInteger. I want to multiply the former by the latter, so I'll have to convert the integer. This is what I came up with, after some trial and error.
NSDecimalNumber *factor = (NSDecimalNumber*) [NSDecimalNumber numberWithInteger:myInteger];
It feels like I'm really driving the point home:
Hi there, I want an NSDecimalNumber, let's call it factor.
By the way, just so you know, I want that to be an NSDecimalNumber, if that'd be possible.
So could you give me an NSDecimalNumber? Here, I'll give you an integer to use as a source.
Is it supposed to be this verbose? Or am I messing up somewhere?
The (NSDecimalNumber*) type-cast is "necessary" because +numberWithInteger: is an NSNumber method that returns an NSNumber object. However, this is actually going to cause problems, because it's returning an NSNumber object, not an NSDecimalNumber. (How to use NSDecimalNumber?)
To get your integer into a decimal number, simply do this:
NSDecimalNumber *factor = [NSDecimalNumber decimalNumberWithDecimal: [#(myInteger) decimalValue]];
It's still fairly verbose but two things to bear in mind:
Objective-C is very verbose, by design.
NSDecimalNumber in not intended for basic integer arithmetic, it's intended for use with numbers that are typically represented using scientific notation.
The API you call is a NSNumber convenience constructor which returns an NSNumber -- not necessarily an NSDecimalNumber. A convenience constructor does not need to return a type of the class you message, but an instance of the declared return type. Because NSDecimalNumber is a subclass of NSNumber, an explicit downcast is required when assigning an NSNumber to an NSDecimalNumber.
If a library writer intended to specify the expectation you have in mind (to return an instance of the class you have messaged), instancetype would be used for the return type. Unfortunately, it is a rather new keyword and does not exist in all places it possibly could exist. If instancetype had been used, the cast would not be necessary.
Before instancetype existed, a simple id was the convention. With id, no cast is required and no type checking performed when assigning/initializing a variable of an Objective-C type. For example: NSArray * array = [NSString string]; would not be flagged by the compiler if the return type were id, but it would be flagged if the return type were instancetype. NSMutableString * string = [NSMutableString string]; would be flagged by neither, but it would be flagged if +string's return type were declared + (NSString *)string;.

Resources