ARC unavailable methods in Swift - ios

I was able to see an interesting case using
Estimote nearables SDK
They have a class ESTNearable with property called zone.
// ENUM
typedef NS_ENUM(NSInteger, ESTNearableZone ) {
ESTNearableZoneUnknown = 0,
ESTNearableZoneImmediate,
ESTNearableZoneNear,
ESTNearableZoneFar,
};
// CLASS
#interface ESTNearable : NSObject <NSCopying, NSCoding>
// ...
#property (nonatomic, assign, readonly) ESTNearableZone zone;
// ...
#end
So when I try to use this method in Swift, compiler fails with that error:
As I understand there is some kind of compiler bug and for some reason it believes that I want to use old zone method from NSObject - (struct _NSZone *)zone OBJC_ARC_UNAVAILABLE; I can use other specific properties of that class without any problems.
As I use an SDK I can not change the name of the zone method. I believe I can write some kind of obj-c category, add some new method there, which will return value of original one, but I do not want to add obj-c classes in my project.
Is there any possibility to call this method from swift as I believe correct zone method will be called for class instances?
Thanks in advance!

Here I found the same question. I answered more deeply there. I could not find something more good, so I went ahead with my old assumptions.
I Added this category to Bridging Header. It worked fine.
#import <EstimoteSDK/EstimoteSDK.h>
#interface ESTNearable (Ex)
/// Solving the compiler problem that "zone" method is unavailable in Swift
#property (readonly) ESTNearableZone nearableZone;
#end
// Implementation
#implementation ESTNearable (Ex)
- (ESTNearableZone)nearableZone
{
return self.zone;
}
#end
After that I just used nearableZone method in Swift
var zone = someNearable.nearableZone

Related

Accessing Objective-c base class's instance variables from a Swift class

Having an Objective c base class:
#interface ObjcClass : NSObject {
NSString *aVariable_;
}
And a swift sub-class:
class SwiftClass : ObjcClass {
func init() {
// aVariable_ can't be accessed here. An Objective-c derived
// class has direct access to it's super's instance variables!
}
}
How do I access ObjcClass aVariable_ from within SwiftClass?
Great query. We have tried to hard to get this done. The only working solution I found
get value by using self.valueForKey("aVariable_")
set value using self.setValue("New Value", forKey: "aVariable_")
Hope that helps. Possible solution without altering super class.
I couldn't find a "proper" way to do this, but I needed badly for it to work. My solution was to create a simple getter method in my Objective C superclass, like this:
header file
#interface ObjcClass : NSObject {
NSString *myVariable;
}
- (NSString *)myVariable;
in the implementation file
- (NSString *)myVariable {
return myVariable;
}
I'd love to hear of a better way of doing it, but this at least works.
I've searched a lot for this.
Eventually I changed my code from:
#interface PrjRec : NSObject {
#public
NSString* name;
}
#end
To:
#interface PrjRec : NSObject {
}
#property NSString* name;
#end
similar to #JasonTyler solution.
Then I can access to my object property from Swift code with simple dot notation <object instance>.name,
But I needed to change all existing objective-c references from
<object instance>->name
To:
<object instance>.name
or
_name
if inside class unit.
I hope for a better solution too.
This worked as a pretty neat solution for me, just adding a Swift variable like:
var myInstanceVar: String {
return self.value(forKey: "myInstanceVar") as! String
}
If you are willing to have a property, then you can create the property to fit your needs.
#interface ObjcClass : NSObject {
NSString *aVariable_;
}
#property (nonatomic) NSString *aVariable_;
...
#implementation ObjcClass
#synthesize aVariable_ = aVariable_;
This allows the variable to be accessed as inst->aVariable_ or as inst.aVariable_. In the Objective C class the variable can be accessed as aVariable_ or self.aVariable_.
I seriously don't know why anyone does instance variables anymore (for one, they're private by default) vs properties. See Giorgio Calzolato's answer on this (apart from his last line about looking for a better solution - that IS the best solution :) ).
In my case I already had a property and was extra perplexed over why it didn't work. But I realized that the property had a custom time and it needed to be added into my SDK-Bridging-Header.h file.
So if your property is set to a custom type like this:
#property (nonatomic, weak) IBOutlet SDKMyCustomObject *customObject;
...then remember to add it to the bridging header.

Property declaration craziness iOS 7

I am at my wits end with a property declaration in a iOS class. In my .h file I have the following declaration :
#property (strong, nonatomic)NSString *sessionID;
In my .m file I have this code :
- (void)setSessionID:(NSString *)aSessionID
{
_sessionID = aSessionID;
// Custom code to set this in a global context
}
This is all fine and compiles with no issues. Now I need to have the sessionID return a default value if nothing is set, however the moment I add this line :
- (NSString *)sessionID
{
return _sessionID ? _sessionID : #"defaultSession";
}
then the first line in the setSessionID:
_sessionID = aSessionID;
causes an error with "Use of undeclared function _sessionID. Did you mean aSessionID", I am at my wits end to figure out what is causing it.. I have so many classes with variables and have never seen this before... what is causing this? I restarted Xcode, cleaned out the project and no luck.. If I remove the - (NSString *)sessionID method, then it stops complaining.. but the moment I add the method declaration the Xcode marks it as an error.
Anypointers accepted! :)
Edit: I also noticed, that in this class if I add any property accessor method it complains about the ivar.. e.g. I have another property declared
#property (strong, nonatomic) NSString *userEmail
The moment I add -(NSString *)userEmail, the ivar _userEmail usage above it all becomes undeclared.. :(
If you override both the setter and getter of a property, the compiler will not automatically synthesize the backing ivar for you. You need to do a manual synthesis,
#synthesize sessionID = _sessionID;

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.

When to declare something in category .m file or in header .h file? [duplicate]

This question already has answers here:
Why is there another #interface inside the.m file? [duplicate]
(6 answers)
Closed 9 years ago.
As we know, normally we used to declare our class instance variables, properties, method declarations in class header file (.h).
But we can do the same things, in .m file, using blank category.
So my question is: what should be declared in .h file and what should be declared in .m file - and why?
Regards,
Mrunal
New Edit:
Hi all,
If you refer to newly added Apple examples over developer.apple.com - they are now declaring their IBOutlets and IBActions in .m file itself and that too with property declaration. But we can achieve the same thing by declaring those references in .h file in class private member section.
Then why are they declaring those in .m file and as properties, any idea?
-Mrunal
But we can do the same things, in .m file, using blank category.
A class continuation.
Normally, you choose to declare something in the header if it is intended to be public -- used by any client. Everything else (your internals) should typically go in the class continuation.
I favor encapsulation -- Here's my approach:
variables
Belongs in the class continuation or #implementation. Exceptions are very, very rare.
properties
Typically belongs in the class continuation in practice. If you want to give subclasses the ability to override these or to make these part of the public interface, then you could declare them in the class declaration (the header file).
method declarations
More in the class continuation than in the class declaration. Again, if it is meant to be used by any client it would belong in the class declaration. Often, you won't even need a declaration in the class continuation (or class declaration) -- the definition alone is adequate if it is private.
Basically, in the header file (.h) you declare your public API, while in the implementation file (.m) you declare your private API.
Visibility in Objective-C
You can also find the answer here
It's mostly up to you.
The .h file is like the description of your class.
It's smart to only put in the .h file what's really important to be visible from the outside of the class, especially if you're working with other developers.
It will help them to understand more easily what methods/properties/variables they can use, rather than having a whole list of things they don't.
Usually you want to use blank category in .m file for declaration of private properties.
// APXCustomButton.m file
#interface APXCustomButton ()
#property (nonatomic, strong) UIColor *stateBackgroundColor;
#end
// Use the property in implementation (the same .m file)
#implementation APXCustomButton
- (void)setStyle:(APXButtonStyle)aStyle
{
UIColor *theStyleColor = ...;
self.stateBackgroundColor = theStyleColor;
}
#end
If you try to access property declared in black category outside .m file, you will receive undeclared property compiler error:
- (void)createButton
{
APXCustomButton *theCustomButton = [[APXCustomButton alloc] init];
theCustomButton.stateBackgroundColor = [UIColor greenColor]; // undeclared property error
}
In most cases, if you want add new method/properties to an existing class without subclassing, then you want declare category in .h file and implementation of declared methods in .m file
// APXSafeArray.h file
#interface NSArray (APXSafeArray)
- (id)com_APX_objectAtIndex:(NSInteger)anIndex;
#end
// APXSafeArray.m file
#implementation NSArray
- (id)com_APX_objectAtIndex:(NSInteger)anIndex
{
id theResultObject = nil;
if ((anIndex >= 0) && (anIndex < [self count]))
{
theResultObject = [self objectAtIndex:anIndex];
}
return theResultObject;
}
#end
Now you can use "com_APX_objectAtIndex:" method wherever "APXSafeArray.h" is imported.
#import "APXSafeArray.h"
...
#property (nonatomic, strong) APXSafeArray *entities;
- (void)didRequestEntityAtIndex:(NSInteger)anIndex
{
APXEntity *theREquestedEntity = [self.entities com_APX_objectAtIndex:anIndex];
...
}

property not found on object Type (custom) xcode

the strangest thing happened. Although I don't think I touched anything in that class, suddenly it started telling me it couldn't find an array in a class...
Here are the errors:
basically it cannot access the mutable array in baseobject (custom Car.h type)
(semantic issue: property objectReadyForCoreDatabase not found in object of type CarPacket (false, because it is declared))
if([baseObject.objectsReadyForCoreDataBaseInput count]<kLenght )
{
}
car packet .h
#import <Foundation/Foundation.h>
#import "ResponsePacket.h"
#interface CarPacket : ResponsePacket
#property (nonatomic, copy) NSString *objectID;
#property (nonatomic, retain) NSMutableArray *objectsReadyForCoreDataBaseInput;
#property (nonatomic, assign) NSInteger timeStamp;
#end
It is weird because on the same page where I get the error if I type object.objectID it recognizes that but not object.objectReadyForCoreDataBaseInput (also it just suddenly stopped working)
Please let me know if you have any ideas... Thank you
I tried restoring to previous snapshots and it had no effect... it still showed the error (even though I know on that date it didn't)
You haven't shared much about the context of where you're making the call (and seeing the error). That said, my guess would be one of two things: The calling class isn't familiar with the receiving class (CarPacket), or, the calling class doesn't know that baseObject is a CarPacket.
Where are you calling from? Make sure the calling class imports the headers. Since I don't know where you're calling from, let's say it's from within UnknownClass:
UnknownClass.m
#import UnknownClass.h
#import CarPacket.h // This should make your class familiar
#implementation UnknownClass
The other thing is that you need to make sure that at the time you're touching the baseObject, your UnknownClass instance knows that it is dealing with a CarPacket instance, e.g.:
- (void)someMethodOfUnknownClass
{
CarPacket *baseObject = (CarPacket *)baseObject; // Cast baseObject if it hasn't been declared as a CarPack in scope...
if([baseObject.objectsReadyForCoreDataBaseInput count]<kLenght )
{
}
}

Resources