readwrite and readonly mutually exclusive - ios

How can I go about achieving this
Property has to be readwrite for inner implementation in class
Property has to be readonly for external interaction to instances of the class

In Objective-C:
MyObject.h
#interface MyObject : NSObject
#property (nonatomic, readonly, strong) NSString *myProperty;
#end
MyObject.m
// Class extension
#interface MyObject ()
// Redeclare property read-write
#property (nonatomic, readwrite, strong) NSString *myProperty;
#end
#implementation MyObject
...
In Swift:
class MyObject {
private(set) var myProperty: String
...

Try like the following example
In your .h:
#property(nonatomic, retain, readonly) NSDate* theDate;
In your .m:
#interface TheClassName()
#property(nonatomic, retain, readwrite) NSDate* theDate;
#end

Related

Best practices for JSONModel and polymorphism

How do you deal with subclassing collection attributes in JSONModel?
Let's say I have these two endpoints with different responses of the same "product object".
domain.com/api/1.0/getProductList
domain.com/api/1.0/getProductDetails/productId
I wrote some example code below to show you my issue:
// ProductListModel
#interface ProductListModel : JSONModel
#property (nonatomic, strong) NSNumber *productId;
#property (nonatomic, strong) NSNumber *userId;
#property (nonatomic, strong) NSArray<OrderListModel> *orders;
#end
// ProductDetailModel
#interface ProductDetailModel : ProductListModel
#property (nonatomic, strong) NSURL *productImageUrl;
#property (nonatomic, strong) NSArray<OrderDetailModel> *orders;
#end
// OrderListModel
#protocol OrderListModel <NSObject>
#end
#interface OrderListModel : JSONModel
#property (nonatomic, strong) NSNumber *orderId;
#property (nonatomic, strong) NSNumber *price;
#end
// OrderDetailModel
#protocol OrderDetailModel <NSObject>
#end
#interface OrderDetailModel : OrderListModel
#property (nonatomic, strong) NSURL *orderImageUrl;
#end
The ProductDetailModel wants the same inherited attributes as ProductListModel, but it wants the orders array in the subclassed type.
However this leads to a compiler warning:
Property type 'NSArray<OrderDetailModel> *' is incompatible with type
'NSArray<OrderListModel> *' inherited from 'ProductListModel'
I found this related SO post but I'd rather not monkey patch the JSONModel library.
Edit #1:
This has been discussed in the #574, and #229 github issues before but requires a "type" string to determine what class to instantiate. This requires a change on the backend API.
Is there a way to do this without changing the backend API?
You can't override the property in the subclass to have a different type as it will violate the Liskov substitution principle - #Paulw11
For future readers, here's how the updated example code would look like:
// ProductBaseModel
#interface ProductBaseModel : JSONModel
#property (nonatomic, strong) NSNumber *productId;
#property (nonatomic, strong) NSNumber *userId;
#end
// ProductListModel
#interface ProductListModel : ProductBaseModel
#property (nonatomic, strong) NSArray<OrderListModel> *orders;
#end
// ProductDetailModel
#interface ProductDetailModel : ProductBaseModel
#property (nonatomic, strong) NSURL *productImageUrl;
#property (nonatomic, strong) NSArray<OrderDetailModel> *orders;
#end
// OrderListModel
#protocol OrderListModel <NSObject>
#end
#interface OrderListModel : JSONModel
#property (nonatomic, strong) NSNumber *orderId;
#property (nonatomic, strong) NSNumber *price;
#end
// OrderDetailModel
#protocol OrderDetailModel <NSObject>
#end
#interface OrderDetailModel : OrderListModel
#property (nonatomic, strong) NSURL *orderImageUrl;
#end

What will happen if my class conforms to two protocols having same property?

Let's say I have two protocols
#protocol Playlist<NSObject>
#property(nonatomic, copy) NSString *title;
#property(nonatomic, assign) NSUInteger trackCount;
#end
and another as
#protocol Album<NSObject>
#property(nonatomic, copy) NSString *name;
#property(nonatomic, assign) NSUInteger trackCount;
#end
and there is a class which conforms to these protocols
.h file
#interface MusicLibrary <Playlist, Album>
#end
.m file
#implementation MusicLibrary
#synthesize title;
#synthesize name;
#synthesize trackCount;
#end
Which trackCount property will it refer to? Can I use trackCount twice?
It surely do not give any compile time error.
It looks to me that you are modeling your data wrong. The way you have it setup a musicLibrary is BOTH a playlist and an album. I think a more correct model would have a MusicLibrary containing many playlist and many albums. Something like:
#property (nonatomic, strong) NSArray<Album>* albums;
#property (nonatomic, strong) NSArray<Playlist>* playlists;

How to bind Objective-C library with protocol and interface have same name

I'm binding a iOS SDK. But the Sharpie confused about this
#interface ALBBQuPaiService : NSObject<ALBBQuPaiService>
The last ALBBQuPaiService is #protocol ALBBQuPaiService
I have tried to change ApiDefinition code like this:
[Protocol(Name = "ALBBQuPaiService"), Model]
interface ALBBQuPaiServiceProtocol
{
...
}
[BaseType (typeof(NSObject), Name = "ALBBQuPaiService")]
interface ALBBQuPaiService : ALBBQuPaiServiceProtocol
{
// +(instancetype)sharedService;
[Static]
[Export ("sharedService")]
ALBBQuPaiService SharedService ();
// #property (nonatomic, weak) id<QupaiSDKDelegate> _Nullable delegte;
[NullAllowed, Export ("delegte", ArgumentSemantic.Weak)]
QupaiSDKDelegate Delegte { get; set; }
}
Finally, I got runtime time exception: unrecognized selector sent to instance 0x7c73f740
Any body can help me? Thanks in advance.
My SDK link
------------------- Update 1: add header file code -------------------------
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger,QupaiSDKWatermarkPosition){
QupaiSDKWatermarkPositionTopRight,
QupaiSDKWatermarkPositionBottomRight,
};
typedef NS_ENUM(NSInteger,QupaiSDKCameraPosition){
QupaiSDKCameraPositionBack,
QupaiSDKCameraPositionFront,
};
#protocol QupaiSDKDelegate;
#protocol ALBBQuPaiService
-(NSString *) getSdkConfigVersion:(NSString *) platformName
sdkVersion:(NSString *) sdkVersion;
-(void) getSdkConfigVersion:(NSString *) platformName
sdkVersion:(NSString *) sdkVersion
success:(void (^)(NSString *rpcResult))success
failure:(void (^)(NSError *rpcError))failure;
#property (nonatomic, weak) id<QupaiSDKDelegate> delegte;
#property (nonatomic, assign) BOOL enableBeauty;
#property (nonatomic, assign) BOOL enableImport;
#property (nonatomic, assign) BOOL enableMoreMusic;
#property (nonatomic, assign) BOOL enableVideoEffect;
#property (nonatomic, assign) BOOL enableWatermark;
#property (nonatomic, assign) CGFloat thumbnailCompressionQuality;
#property (nonatomic, strong) UIColor *tintColor;
#property (nonatomic, strong) UIImage *watermarkImage;
#property (nonatomic, assign) QupaiSDKWatermarkPosition watermarkPosition;
#property (nonatomic, assign) QupaiSDKCameraPosition cameraPosition;
- (UIViewController *)createRecordViewControllerWithMinDuration: (CGFloat)minDuration
maxDuration:(CGFloat)maxDuration
bitRate:(CGFloat)bitRate;
- (UIViewController *)createRecordViewController;
- (void)updateMoreMusic;
#end
#protocol QupaiSDKDelegate <NSObject>
- (void)qupaiSDK:(id<ALBBQuPaiService>)sdk compeleteVideoPath:(NSString *)videoPath thumbnailPath:(NSString *)thumbnailPath;
#optional
- (NSArray *)qupaiSDKMusics:(id<ALBBQuPaiService>)sdk;
- (void)qupaiSDKShowMoreMusicView:(id<ALBBQuPaiService>)sdk viewController:(UIViewController *)viewController;
#end
#interface ALBBQuPaiService : NSObject<ALBBQuPaiService>
+(instancetype)sharedService;
#property (nonatomic, weak) id<QupaiSDKDelegate> delegte;
#end
Remember that all the obj-c protocol act as a abstract class I recommend to put "protocol, model and set base type as nsobject, another thing all the methods or properties maked as a "required" you need to specify it as Abstract.
[Protocol, Model]
[BaseType (typeof(NSObject))]
interface myAwesomeDelegate
{
[Abstract]
[Export(...)]
void myRequiredMethod(uint param1)
[Export(...)]
void anotherMethod()
}
I recommend to use the objective sharpie tool it support .framework files using version 3.X with the command framework bind -f myFramework.framework
for more info about it check https://developer.xamarin.com/guides/cross-platform/macios/binding/objective-sharpie/tools/ or also you can check in the xamarin Github bindings https://github.com/mono/monotouch-bindings, if you have any specific question about bindings please let me know

Converting jsonarray (having different type) to model array using JSONModel Library

I have one problem in converting JSON array to model. I am using JSONModel library.
#protocol PTTemplateModel <NSObject>
#end
#protocol PTProfileTemplateModel <PTTemplateModel>
#end
#protocol PTCategoryTemplateModel <PTTemplateModel>
#end
#interface PTTemplateModel : JSONModel
#property (nonatomic, assign) TemplateType type;
#property (nonatomic, copy) NSString* templateID;
#end
#interface PTProfileTemplateModel : PTTemplateModel
#property (nonatomic, copy) NSString* logoURL;
#property (nonatomic, copy) NSString* title;
#end
#interface PTCategoryTemplateModel : PTTemplateModel
#property (nonatomic, strong) NSString* category;
#end
#interface PTModel : JSONModel
#property (nonatomic, copy) NSString* title;
#property (nonatomic, strong) NSArray< PTTemplateModel>* templates; // PTTemplateModel
Here templates array can have both PTProfileTemplateModel and PTCategoryTemplateModel.
JSON Input:
{"title":"Core","templates":[{"type":0,"templateID":"","logoURL":"", "title":"data"},{"type":1,"templateID":"","category":"DB"}]}
What I need is according to type I have to get CategoryTemplate or ProfileTemplate. But after conversion I am getting just PTTemplateModel type.
I know that I have specified protocol type as PTTemplateModel. But how do I get different type of model according to given data.
I tried:
#property (nonatomic, strong) NSArray< PTTemplateModel>* templates;
#property (nonatomic, strong) NSArray<PTProfileTemplateModel, PTCategoryTemplateModel>* templates;
#property (nonatomic, strong) NSArray< PTTemplateModel , PTProfileTemplateModel, PTCategoryTemplateModel>* templates;
None of them works.
Any suggestions?
Why not try BWJSONMatcher, it helps you work with json data in a very very neat way:
#interface PTModel : NSObject<BWJSONValueObject>
#property (nonatomic, strong) NSString *title;
#property (nonatomic, strong) NSArray *templates;
#end
#interface PTTemplateModel : NSObject
#property (nonatomic, assign) TemplateType type;
#property (nonatomic, strong) NSString *templateID;
#property (nonatomic, strong) NSString *logoURL;
#property (nonatomic, strong) NSString *title;
#property (nonatomic, strong) NSString *category;
#end
In the implementation of PTModel, implement the function typeInProperty: declared in protocol BWJSONValueObject:
- (Class)typeInProperty:(NSString *)property {
if ([property isEqualToString:#"templates"]) {
return [PTTemplateModel class];
}
return nil;
}
Then you can use BWJSONMatcher to get your data model within one line:
PTModel *model = [PTModel fromJSONString:jsonString];
Detailed examples of how to use BWJSONMatcher can be found here.

Access private interface property by public method

I would like to ask you some opinion about what I'm doing. I know it works, but I'm not sure is proper to do what I'm doing.
I have a superclass Building that need to expose two NSString, name and description. No one should be able to modify those variables apart their subclasses.
To get this result I have created two public method on the base class:
#interface Building : NSObject
- (NSString *)name;
- (NSString *)description;
#end
Then on each subclass I'm creating a private interface with name and description properties and let the magic happen.
#interface Barrack()
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *description;
#end
#implementation Barrack
#synthesize name, description;
...
#end
What you guys think about this?Is this a proper way to get this kind of result, anyone have better ideas about this topic?
Thanks for your opinion.
Best,
Enrico
Declare readonly properties in the interface, readwrite in the implementation class extension. No need for #synthesize. This is one of the main reason class extensions were added to Objective-C.
in Building.h
#interface Building : NSObject
#property (nonatomic, strong, readonly) NSString *name;
#property (nonatomic, strong, readonly) NSString *description;
#end
In Barrack.m
#interface Barrack ()
#property (nonatomic, strong, readwrite) NSString *name;
#property (nonatomic, strong, readwrite) NSString *description;
#end
#implementation Barrack
...
#end

Resources