#import "CacheManager.h"
#implementation CacheManager
//Get an Instance of Cache Manager Class
+(instancetype) getInstance {
static dispatch_once_t once;
static CacheManager *sinstance=nil;
if(sinstance==nil){
dispatch_once(&once, ^{
sinstance = [[CacheManager alloc]init];
});
}
return sinstance;
}
#import "Resturant.h"
#implementation Resturant
-(instancetype) initWithDictionary:(NSDictionary*)dictionary {
self = [super init];
if (self && dictionary) {
self.iD=dictionary[KZOMATO_RESTURANT_KEY][KZOMATO_RESURANT_ID];
self.name=dictionary[KZOMATO_RESTURANT_KEY][KZOMATO_RESTURANT_NAME];
self.url=dictionary[KZOMATO_RESTURANT_KEY][KZOMATO_RESTURANT_URL];
self.photoURL=dictionary[KZOMATO_RESTURANT_KEY][KZOMATO_RESTURANT_PHOTO_URL];
self.rating=dictionary[KZOMATO_RESTURANT_KEY][KZOMATO_RESTURANT_USER_RATING_KEY][KZOMATO_AGGREGATE_RATTING];
self.adress=dictionary[KZOMATO_RESTURANT_KEY][KZOMATO_LOCATION_KEY][KZOMATO_ADRESS_KEY];
self.averageCostForTwo=dictionary[KZOMATO_RESTURANT_KEY][KZOMATO_AVERAGE_COST_KEY];
self.image = nil;
self.imageLoaded = FALSE;
[self getImage:^(UIImage *image) {
self.image=image;
}];
return self;
}
return nil;
}
//method to get image from Cached Data
-(void) getImage :(void (^)(UIImage * image))callBack {
// This line of code getInstance is showing error
[[CacheManager getInstance]imageForURL:self.photoURL withCompletionHandler:^(UIImage *image) {
self.imageLoaded = TRUE;
callBack(image);
}];
}
#end
Related
I have a framework where I have to send the captured image back to the callee. So I have to wait for the delegate to finish
I am using dispatch_asyc to wait for the async operation of the delegate method.
But the delegate method is not called and the application is stuck NSLog(#"dispatch_get_global_queue"); here.
I have added my code below. Please help
NoPreviewCamera.h
#import <AVFoundation/AVFoundation.h>
NS_ASSUME_NONNULL_BEGIN
#interface NoPreviewCamera : NSObject <AVCapturePhotoCaptureDelegate>
#end
static NoPreviewCamera *noPreviewCamera = nil;
static NSString *imageDataBase64 = nil;
static dispatch_group_t group = nil;
NS_ASSUME_NONNULL_END
NoPreviewCamera.m
#import "NoPreviewCamera.h"
AVCaptureSession *captureSession;
AVCapturePhotoOutput *photoOutput;
AVCapturePhotoSettings *photoSetting;
AVCaptureConnection *captureConnection;
id<AVCapturePhotoCaptureDelegate> avCaptureDelegate;
#interface NoPreviewCamera ()
#end
#implementation NoPreviewCamera
+ (void) initCaptureSession {
captureSession = [[AVCaptureSession alloc] init];
if([captureSession canSetSessionPreset: AVCaptureSessionPresetPhoto] ) {
[captureSession setSessionPreset:AVCaptureSessionPresetPhoto];
}
[captureSession startRunning];
}
+ (void) setNewPhotoSetting {
photoSetting = [AVCapturePhotoSettings photoSettingsWithFormat:#{AVVideoCodecKey : AVVideoCodecTypeJPEG}];
[photoOutput setPhotoSettingsForSceneMonitoring:photoSetting];
}
+ (void) initInputDevice: (AVCaptureDevice *) inputDevice {
AVCaptureDeviceInput *deviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:inputDevice error:nil];
if ([captureSession canAddInput:deviceInput]) {
[captureSession addInput:deviceInput];
}
}
+ (void) initOuput {
photoOutput = [[AVCapturePhotoOutput alloc] init];
if ([captureSession canAddOutput:photoOutput]) {
[captureSession addOutput:photoOutput];
}
}
+ (AVCaptureDevice *) frontFacingCameraIfAvailable {
AVCaptureDeviceDiscoverySession *captureDeviceDiscoverySession = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:#[AVCaptureDeviceTypeBuiltInWideAngleCamera] mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionFront];
NSArray *captureDevices = [captureDeviceDiscoverySession devices];
if (!captureDevices || !captureDevices[0]){
return [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
} else {
return captureDevices[0];
}
}
+ (NSString *) takePictureWithNoPreviewFrontFacingCamera {
NSLog(#"NoPreviewCameraNoPreviewCameraNoPreviewCameraNoPreviewCamera");
noPreviewCamera = [[NoPreviewCamera alloc]init];
[NoPreviewCamera initCaptureSession];
[NoPreviewCamera initInputDevice:[NoPreviewCamera frontFacingCameraIfAvailable]];
[NoPreviewCamera initOuput];
[NoPreviewCamera setNewPhotoSetting];
captureConnection = nil;
for (AVCaptureConnection *connection in photoOutput.connections) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual: AVMediaTypeVideo]) {
captureConnection = connection;
break;
}
}
if (captureConnection) {
break;
}
}
[NoPreviewCamera getOutputPhoto:^(BOOL success) {
NSLog(#"FINNNNNENENEENENENEN %o", success );
}];
return imageDataBase64;
}
+ (void)getOutputPhoto:(void (^) (BOOL success))completion
{
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, kNilOptions), ^{
noPreviewCamera = [[NoPreviewCamera alloc]init];
[photoOutput capturePhotoWithSettings:photoSetting delegate:noPreviewCamera];
NSLog(#"dispatch_get_global_queue");
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"dispatch_get_main_queue");
completion(true);
dispatch_group_leave(group);
});
});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
}
- (void)captureOutput:(AVCapturePhotoOutput *)output didFinishProcessingPhoto:(AVCapturePhoto *)photo error:(nullable NSError *)error
{
NSLog(#"image delegate");
NSData *imageData = [photo fileDataRepresentation];
imageDataBase64 = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
NSLog(#"image captured");
}
- (void)captureOutput:(AVCapturePhotoOutput *)output didCapturePhotoForResolvedSettings:(AVCaptureResolvedPhotoSettings *)resolvedSettings {
NSLog(#"Finised");
}
#end
As I see you creating instance of NoPreviewCamera inside a static method of this class. And setting this instance as delegate. And this "instance" is static property as well. And after you expecting this to call instance methods.
Try to drop it to heap instead.
Make it an object with some reference to.
I'm learning runtime, when I code this:
#implementation Son
- (instancetype)init
{
self = [super init];
if (self) {
[self performSelector:#selector(sel) withObject:nil];
}
return self;
}
id dynamicMethodIMP(id self, SEL _cmd)
{
NSLog(#"%s:dynamic method",__FUNCTION__);
return #"1";
}
+ (BOOL)resolveInstanceMethod:(SEL)sel {
class_addMethod(self.class, sel, (IMP)(dynamicMethodIMP), "##:");
[super resolveInstanceMethod:sel];
return YES;
}
#end
It's running very well.
But when I code this:
#implementation Son
id dynamicMethodIMP(id self, SEL _cmd)
{
NSLog(#"%s:dynamic method",__FUNCTION__);
return #"1";
}
+ (BOOL)resolveClassMethod:(SEL)sel {
class_addMethod(self.class, sel, (IMP)(dynamicMethodIMP), "##:");
[super resolveClassMethod:sel];
return YES;
}
#end
//Other file
[Son performSelector:#selector(sel) withObject:nil];
It crashed with:
+[Son sel]: unrecognized selector sent to class 0x10da8a588
What should I do to implement the method + (BOOL)resolveClassMethod:(SEL)sel?
Replace self.class with object_getClass
+ (BOOL)resolveClassMethod:(SEL)sel {
class_addMethod(object_getClass(self), sel, (IMP)(dynamicMethodIMP), "##:");
[super resolveClassMethod:sel];
return YES;
}
Reason:
object_getClass will return meta class if parameter is a class object。
If you read Chinese, you can read my blog to see more details about meta class.
I have singleton to use websocket connection, when _srWebSocket = nil, will returned new _srWebSocket, but when _srWebSocket connected, will returned nil
#interface SocketManager : NSObject
#property (nonatomic, weak) SRWebSocket *srWebSocket;
+ (SocketManager *) sharedInstance;
#end
#implementation SocketManager
#synthesize srWebSocket = _srWebSocket;
+ (SocketManager *) sharedInstance {
static SocketManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[SocketManager alloc] init];
});
return sharedInstance;
}
- (id)init {
if (self = [super init]) {
NSLog(#"In SocketKeeperSingleton init");
}
return self;
}
- (SRWebSocket *) srWebSocket {
if (!_srWebSocket || _srWebSocket.readyState == SR_CLOSED) {
_srWebSocket = [[SRWebSocket alloc] initWithURL:[NSURL URLWithString:#"wss://...:8000"]];
[_srWebSocket open];
}
return _srWebSocket;
}
#end
Call singleton
srWebSocket = [SocketManager sharedInstance].srWebSocket;
because you have write 'static SocketManager *sharedInstance = nil;' in shareInstance Method .
when this method call every time they send nil .
+ (SocketManager *) sharedInstance {
static SocketManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[SocketManager alloc] init];
});
return sharedInstance;
}
write down this line outside shareInstance method "static SocketManager *sharedInstance = nil;"
You are missing srWebSocket method call,
First way,
Declare one method in singleton.h file
-(void) doInitialSetupOnLaunch;
Add this method somewhere in your singleton.m file,
-(void) doInitialSetupOnLaunch {
//Put your initialized code i mean you can call your method from here & define your properties here.
_srWebSocket = [self srWebSocket];
}
- (SRWebSocket *) srWebSocket {
if (!_srWebSocket || _srWebSocket.readyState == SR_CLOSED) {
_srWebSocket = [[SRWebSocket alloc] initWithURL:[NSURL URLWithString:#"wss://...:8000"]];
[_srWebSocket open];
}
return _srWebSocket;
}
Call it from somewhere,best way you can call from appDelegate.m
Now you are ready to access it by property,
Call singleton
srWebSocket = [SocketManager sharedInstance].srWebSocket;
Or Second way
SRWebSocket * srWebSocket = [[SocketManager sharedInstance] srWebSocket];
init method is declared in NSObject class hence, the client code can create a new instance of my singleton class, is there any way to achieve the real singleton such that client cannot create a new instance.
Just do this:
static SingletonClass *singleton;
+ (SingletonClass *)sharedInstance
{
#synchronized(self) { //For thread safety
if (singleton == nil) {
[[self alloc] init];
}
return singleton;
}
}
-(id)init
{
if (singleton) { //This way init will always return the same instance
return singleton;
}
self = [super init];
if (self) {
singleton = self;
}
return singleton;
}
This is a proper way to do a singleton in objective c
+ (id)sharedManager
{
static dispatch_once_t onceQueue;
static SingletonObjectClass *singleton = nil;
dispatch_once(&onceQueue, ^{
singleton = [[self alloc] init];
});
return singleton;
}
- (id)init {
self = [super init];
if (self) {
//.....
}
return self;
}
init method is for initialization of instance variables. on its own will not create the object. Alloc, copy methods needs to be overridden to achieve a real single ton.
Hope this should clarify.
+ (id)alloc {
NSLog(#"%#: use +sharedInstance instead of +alloc", [[self class] name]);
return nil;
}
+ (id)new {
return [self alloc];
}
+ (SingletonClass *)sharedInstance {
static SingletonClass *myInstance = nil;
if (!myInstance)
{
myInstance = [[super alloc] init];
}
return myInstance;
}
You can return a static object of the class each time, making it a singleton.
#implementation Singleton
#synthesize testVar;
+ (Singleton*) sharedObject {
static Singleton * myInstance = nil;
if (myInstance == nil) {
myInstance = [[[self class] alloc] init];
testVar = 5;
// Set default values if needed
return myInstance;
}
To access object and its members:
[[Singleton sharedObject] testVar]
How can i make sure user do not call init, instead client should call sharedSingleton to get a shared instance.
#synthesize delegate;
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
}
return self;
}
+ (LoginController *)sharedSingleton
{
static LoginController *sharedSingleton;
#synchronized(self)
{
if (!sharedSingleton)
sharedSingleton = [[LoginController alloc] init];
CdtMiscRegisterConnectionChangeListenerObjc(test_ConnectionChangeListenerCallback);
return sharedSingleton;
}
}
I've seen it done two ways.
Throw an exception inside init.
Have the object returned by init be your singleton object.
Just to be clear, though, don't do this. It's unnecessary and will make your singletons overly difficult to test and subclass.
edit to add examples
Throw an exception in init
- (instancetype)init {
[self doesNotRecognizeSelector:_cmd];
return nil;
}
- (instancetype)initPrivate {
self = [super init];
if (self) {
}
return self;
}
+ (instancetype)sharedInstance {
static MySingleton *sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] initPrivate];
});
return sharedInstance;
}
Have init return your singleton
- (instancetype)init {
return [[self class] sharedInstance];
}
- (instancetype)initPrivate {
self = [super init];
if (self) {
}
return self;
}
+ (instancetype)sharedInstance {
static MySingleton2 *sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] initPrivate];
});
return sharedInstance;
}
Use UNAVAILABLE_ATTRIBUTE abolish init method, and implement initPrivate
+ (instancetype)shareInstance;
- (instancetype)init UNAVAILABLE_ATTRIBUTE;
+ (instancetype)new UNAVAILABLE_ATTRIBUTE;
implement
+ (instancetype)shareInstance {
static MyClass *shareInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
shareInstance = [[super allocWithZone:NULL] initPrivate];
});
return shareInstance;
}
- (instancetype)initPrivate {
self = [super init];
if (self) {
}
return self;
}
// MARK: Rewrite
+ (id)allocWithZone:(struct _NSZone *)zone {
return [MyClass shareInstance];
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
Short answer: you can't; Objective-C has no concept of private methods.
Check out the answer to this similar question.
You can't make methods private in Objective-C. You could raise a NSException if the wrong initializer is invoked.
- (id)init
{
[NSException exceptionWithName:#"InvalidOperation" reason:#"Cannot invoke init." userInfo:nil];
}