Assigning value to a property of a readonly object - ios

I have 2 classes as per below:
Class ModelA.h
#interface ModelA : NSObject
#property (nonatomic, strong) NSArray *arrayA;
#end
Class ControllerA.m
#interface ControllerA()
# property (nonatomic, copy, readonly) ModelA *modelProperty;
#end
#implementation ControllerA
- (void)someMethod:(NSArray *)sampleArray
{
self.modelProperty.arrayA = sampleArray;
}
If I try to assign something to self.modelProperty, I get a build error which says I cannot since its a readonly property. But I assign something to its property it XCode doesn't give any error i.e. self.modelProperty.arrayA = sampleArray just builds fine. However when I debug through it and print self.modelProperty.arrayA I get nil even though sampleArray has data in it.
Question: Is it possible to assign values to a property of a readonly object?

Is it possible to assign values to a property of a readonly object?
Er, sort of. The language you used is slightly confusing. It isn't a readonly object; it's a readonly property. And it is possible to assign values to the object stored in a readonly property.
readonly just means that you can't set that property -- there is no setModelProperty: setter method.
It does not mean that the target of the object is immutable. It's not analogous to const. All it means is that you can't set the property.
The reason you're seeing nil is that any message sent to nil returns nil.
self.modelProperty.arrayA
Is the same as:
[[self modelProperty] arrayA]
If modelProperty is nil (which it is, from the code you've shown), this is the same as:
[nil arrayA]
Which returns nil -- in the same way that [nil anyMethod] returns nil.
Final note: you have copy set as the memory policy for the modelProperty property, but the ModalA class doesn't appear implement the NSCopying protocol. Are you sure you don't want strong?

Try: _modelProperty = sampleArray

Related

insert text from textview to string return NSMallocBlock in the string objective c

I have a textview that user can edit, when I try to insert the text from the textview to a local property from type Nsstring, I got in this property NSMallocBlock. what is the reason? thank you!
this is the defintaion of cartItemComment:
#property (nonatomic, assign) NSString * cartItemComment;
and this is the code:
CartItem *cartItem = [[CartItem alloc]init];
cartItem.cartItemComment = itemRequestText.text;
cartitem is a object that have a property cartItemComment, after those lines, I got NSMallocBlock in cartItemComment.
another problem, i can get a weird string like this:
assign property attribute applies to primitive types, it does nothing with the object reference. When an object is assigned to this property, it is deallocated (if it is not retained by some other object), and all you have left is a pointer to the memory where it once was. Never use assign to store objects.
weak is similar to assign, with the only difference that when the object referenced by this property is deallocated (retain count reaches zero), it is set to nil, so you would never have a pointer to garbage memory.
strong retains the object and prevents it from being deallocated.
Your property should be declared like so:
#property (nonatomic, strong) NSString *cartItemComment;

Why is instancetype used?

Can someone please explain to me (in simple terms) why an instancetype is used in Objective-C?
- (instancetype) init {
self = [super init];
if (self) {
// Custom initialization
}
return self;
}
It's to increase type safety.
Back in the old days, initialisers just returned an object of type id (any object).
With normal initialisers (those that begin with "init", "alloc" or "new"), this wasn't usually a problem. The compiler would automatically infer the type that it returned and therefore restrict any method calls on the object to the instance methods of that class.
However, this was a problem with static convenience initialisers or "factory methods" that didn't necessarily follow the same naming convention - therefore it was unable to apply the same type safety.
This means that with a class like this:
#interface Foo : NSObject
+(id) aConvenienceInit;
#end
The compiler would accept code like this:
NSArray* subviews = [Foo aConvenienceInit].subviews;
Why? Because the returned object could be any object, so if you try and access a UIView property - there's no type safety to stop you.
However, now with instancetype, the result you get back is of type of your given instance. Now with this code:
#interface Foo : NSObject
+(instancetype) aConvenienceInit;
#end
...
NSArray* subviews = [Foo aConvenienceInit].subviews;
You'll get a compiler warning saying that the property subviews is not a member of Foo*:
Although it's worth noting that the compiler will automatically convert the return type from id to instancetype if your method begins with "alloc", "init" or "new" - but nonetheless using instancetype wherever you can is a good habit to get into.
See the Apple docs on instancetype for more info.
Imagine two classes:
#interface A : NSObject
- (instancetype)init;
#end
#interface B : A
#end
The init method from A is inherited to B. However, in both classes the method has a different return type. In A the return type is A and in B the return type is B.
There is no other way to declare the return type for initializers correctly. Note that most programming languages with classes don't even have return types for constructors, therefore they completely avoid the issue.
This is the reason why Obj-C needs instancetype but of course it can be used outside initializers, too.
It is important to use instancetype instead of id in Objective-C if you are also using this code in Swift. Consider the following class declaration:
#interface MyObject : NSObject
+ (id)createMyObject;
- (void)f;
#end
If you want to create a MyObject instance in Swift 5.3 with createMyObject and then call f for this object, you will have to do the following:
let a = MyObject.createMyObject()
(a as? MyObject)?.f()
Now replace id with instancetype in MyObject to have the following Swift code:
let a = MyObject.create()
a?.f()
As you can see now, you can use MyObject.create() instead of MyObject.createMyObject(). And you don't need to use (a as? MyObject) since a is defined as MyObject? and not as Any.

#property #synthesize equivalent in swift

I have something like
#property(nonatomic,retain) UIImageView *whiteBfFillUp;
#end
#synthesize locationManager;
I am new to swift coding. Can anyone tell me the equivalent code in swift.
There is no equivalent.
In Swift when you write a varor let in a class or struct declaration you already declaring a property.
Define properties to store values
This is what is written in Swift documentation.
If you are concerned about access control you can use private or public modifiers.
public var somePublicVariable = 0
If you'd like to override properties such as you did in Objective-C you will find useful properties observers such as didSet{} willSet{}.
If you need a a readonly properties you can make the setter private.
public private(set) var hours = 0
If you are only looking for equivalent of property, then you just need to create your class level variables. All class level variables are by default 'strong' or 'retain'. If, however, you want them to be weak then use weak.
This would be something like
var whiteBfFillUp: UIImageView? = nil
The ? at the end means that this is an optional type. If it's not, you would need to assign it some value in the init method, or right there.

Access int from Another Objective-C Class

I've trying to get an int from another class and it just says that the number is 0 (but it's not).
This is in Class2.h:
#interface Class2 : SKScene <SKPhysicsContactDelegate>{
Class1 * class;
}
This is in Class2.m:
NSLog(#"%i", class.thisint);
This is in Class1.h:
#property (assign, nonatomic) int thisint;
This is in Class1.m (in viewDidLoad):
thisint = 5;
The NSLog is being called well after the viewDidLoad method but it just keeps saying 0. How do I get this int from Class1? I don't know if the fact that Class2 is an SKScene affects this...
class is an existing method on NSObject and I would hope that you've just used that name for the purposes of this question - if not, please change the name of the variable, it will only lead to confusion.
What do you see if you log class:
NSLog(#"%#",class);
(Put that next to where your existing log is)
How and where are you assigning to the class variable?
A value of 0 probably means one of two things:
class is nil. This means you haven't assigned it anywhere. You don't magically get a value in a property just because you've declared one
class is a different instance to the one you think it is. This is a common beginner mistake, where you've done something like
class = [[Class2 alloc] init];
Which creates a new instance. You need to get a reference to the existing instance, which I can't tell you how to do without seeing more code.

Reassigning deprecated properties to new properties objective-c

I've got a property that I want to change the name of. Basically I want the old property to return/set the value of the new property so existing code doesn't break, but it'll throw warnings to use the new name.
This is in my header file:
#property (nonatomic, strong) MyClass *newProperty;
#property (nonatomic, strong) MyClass *oldProperty __attribute__((deprecated));
To make oldProperty's getters and setters just set/return newProperty's values in the implementation i'd like to do something like
#synthesize oldProperty=_newProperty;
This throws an error 'oldProperty and newProperty both claim instance variable _newProperty'. Whats the best way to achieve what I want to do? (I'm deprecating and renaming about 30 properties)
Setting the getters/setters manually returns the same error
- (void)setOldProperty:(MyClass *)oldProperty {
_newProperty=oldProperty;
}
- (MyClass *)oldProperty:(MyClass *)oldProperty {
return _newProperty;
}
EDIT: Solution I used with the help of BlackRiders input -------------------------------------------------------------
Interface:
#property (nonatomic, strong) MyClass *newProperty;
- (void)setOldProperty:(MyClass *)oldProperty __attribute__((deprecated));
- (MyClass *)oldProperty __attribute__((deprecated));
Implementation:
- (void)setOldProperty:(MyClass *)oldProperty {
_newProperty=oldProperty;
}
- (MyClass *)oldProperty {
return _newProperty;
}
I would have just one actual property to avoid confusion and name collisions. For example:
property (getter=oldProperty, setter=setOldProperty:) MyClass *newProperty;
You can also optionally create the methods newProperty and setNewProperty:. You can also throw in some #warning statements in the getter and setter you want people to stop using.

Resources