EXC_BAD_ACCESS while using ASyncImageView - ios

I'm trying to run my application on iPhone 6 (iOS 9.3.2) and using XCode 7.3 but the problem is that it is getting crashed everytime I move from one tab to another. The Exception is pointing to this class and the method marked as "error".
Can anyone please help me out with this?
I'm attaching the code for your reference.
Thanks.
//
// AsyncImageView.m
//
#import "AsyncImageView.h"
#import <objc/message.h>
#define MAX_IMAGE_SIZE 1.5 * 1024 * 1024
#define RESIZE_IMG 0
NSString *const AsyncImageLoadDidFinish = #"AsyncImageLoadDidFinish";
NSString *const AsyncImageLoadDidFail = #"AsyncImageLoadDidFail";
NSString *const AsyncImageTargetReleased = #"AsyncImageTargetReleased";
NSString *const AsyncImageImageKey = #"image";
NSString *const AsyncImageURLKey = #"URL";
NSString *const AsyncImageCacheKey = #"cache";
NSString *const AsyncImageErrorKey = #"error";
#interface AsyncImageConnection : NSObject
#property (nonatomic, strong) NSURLConnection *connection;
#property (nonatomic, strong) NSMutableData *data;
#property (nonatomic, strong) NSURL *URL;
#property (nonatomic, strong) NSCache *cache;
#property (nonatomic, strong) id target;
#property (nonatomic, assign) SEL success;
#property (nonatomic, assign) SEL failure;
#property (nonatomic, readonly, getter = isLoading) BOOL loading;
#property (nonatomic, readonly) BOOL cancelled;
- (AsyncImageConnection *)initWithURL:(NSURL *)URL
cache:(NSCache *)cache
target:(id)target
success:(SEL)success
failure:(SEL)failure;
- (void)start;
- (void)cancel;
- (BOOL)isInCache;
#end
#implementation AsyncImageConnection
#synthesize connection = _connection;
#synthesize data = _data;
#synthesize URL = _URL;
#synthesize cache = _cache;
#synthesize target = _target;
#synthesize success = _success;
#synthesize failure = _failure;
#synthesize loading = _loading;
#synthesize cancelled = _cancelled;
- (AsyncImageConnection *)initWithURL:(NSURL *)URL
cache:(NSCache *)cache
target:(id)target
success:(SEL)success
failure:(SEL)failure
{
if ((self = [self init]))
{
self.URL = URL;
self.cache = cache;
self.target = target;
self.success = success;
self.failure = failure;
}
return self;
}
- (UIImage *)cachedImage
{
if ([_URL isFileURL])
{
NSString *path = [[_URL absoluteURL] path];
NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
if ([path hasPrefix:resourcePath])
{
return [UIImage imageNamed:[path substringFromIndex:[resourcePath length]]];
}
}
return [_cache objectForKey:_URL];
}
- (BOOL)isInCache
{
return [self cachedImage] != nil;
}
- (void)loadFailedWithError:(NSError *)error
{
_loading = NO;
_cancelled = NO;
[[NSNotificationCenter defaultCenter] postNotificationName:AsyncImageLoadDidFail
object:_target
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
_URL, AsyncImageURLKey,
error, AsyncImageErrorKey,
nil]];
}
- (void)cacheImage:(UIImage *)image
{
if (!_cancelled)
{
if (image && _URL)
{
BOOL storeInCache = YES;
if ([_URL isFileURL])
{
if ([[[_URL absoluteURL] path] hasPrefix:[[NSBundle mainBundle] resourcePath]])
{
//do not store in cache
storeInCache = NO;
}
}
if (storeInCache)
{
#if RESIZE_IMG
// resize the image before storing
NSData *data = UIImageJPEGRepresentation(image, 1.0);
if (data.length > MAX_IMAGE_SIZE)
{
image = [HFUtils imageWithImage:image scaledBy:MAX_IMAGE_SIZE / (float)data.length];
}
#endif
[_cache setObject:image forKey:_URL];
}
}
NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
image, AsyncImageImageKey,
_URL, AsyncImageURLKey,
nil];
if (_cache)
{
[userInfo setObject:_cache forKey:AsyncImageCacheKey];
}
_loading = NO;
[[NSNotificationCenter defaultCenter] postNotificationName:AsyncImageLoadDidFinish
object:_target
userInfo:[[userInfo copy] autorelease]];
}
else
{
_loading = NO;
_cancelled = NO;
}
}
- (void)processDataInBackground:(NSData *)data
{
#synchronized ([self class])
{
if (!_cancelled)
{
UIImage *image = [[UIImage alloc] initWithData:data];
if (image)
{
//add to cache (may be cached already but it doesn't matter)
[self performSelectorOnMainThread:#selector(cacheImage:)
withObject:image
waitUntilDone:YES];
[image release];
}
else
{
#autoreleasepool
{
NSError *error = [NSError errorWithDomain:#"AsyncImageLoader" code:0 userInfo:[NSDictionary dictionaryWithObject:#"Invalid image data" forKey:NSLocalizedDescriptionKey]];
[self performSelectorOnMainThread:#selector(loadFailedWithError:) withObject:error waitUntilDone:YES];
}
}
}
else
{
//clean up
[self performSelectorOnMainThread:#selector(cacheImage:)
withObject:nil
waitUntilDone:YES];
}
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
self.data = [NSMutableData data];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
//add data
[_data appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[self performSelectorInBackground:#selector(processDataInBackground:) withObject:_data];
self.connection = nil;
self.data = nil;
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
self.connection = nil;
self.data = nil;
[self loadFailedWithError:error];
}
- (void)start
{
if (_loading && !_cancelled)
{
return;
}
//begin loading
_loading = YES;
_cancelled = NO;
//check for nil URL
if (_URL == nil)
{
[self cacheImage:nil];
return;
}
//check for cached image
UIImage *image = [self cachedImage];
if (image)
{
//add to cache (cached already but it doesn't matter)
[self performSelectorOnMainThread:#selector(cacheImage:)
withObject:image
waitUntilDone:NO];
return;
}
//begin load
NSURLRequest *request = [NSURLRequest requestWithURL:_URL
cachePolicy:NSURLCacheStorageNotAllowed
timeoutInterval:[AsyncImageLoader sharedLoader].loadingTimeout];
_connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[_connection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
[_connection start];
}
- (void)cancel
{
_cancelled = YES;
[_connection cancel];
self.connection = nil;
self.data = nil;
}
- (void)dealloc
{
[_connection release];
[_data release];
[_URL release];
[_target release];
[super ah_dealloc];
}
#end
#interface AsyncImageLoader ()
#property (nonatomic, strong) NSMutableArray *connections;
#end
#implementation AsyncImageLoader
#synthesize cache = _cache;
#synthesize connections = _connections;
#synthesize concurrentLoads = _concurrentLoads;
#synthesize loadingTimeout = _loadingTimeout;
+ (AsyncImageLoader *)sharedLoader
{
static AsyncImageLoader *sharedInstance = nil;
if (sharedInstance == nil)
{
sharedInstance = [[self alloc] init];
}
return sharedInstance;
}
+ (NSCache *)defaultCache
{
static NSCache *sharedInstance = nil;
if (sharedInstance == nil)
{
sharedInstance = [[NSCache alloc] init];
}
return sharedInstance;
}
- (AsyncImageLoader *)init
{
if ((self = [super init]))
{
self.cache = [[self class] defaultCache];
_concurrentLoads = 2;
_loadingTimeout = 60.0;
_connections = [[NSMutableArray alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(imageLoaded:)
name:AsyncImageLoadDidFinish
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(imageFailed:)
name:AsyncImageLoadDidFail
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(targetReleased:)
name:AsyncImageTargetReleased
object:nil];
}
return self;
}
- (void)updateQueue
{
//start connections
NSUInteger count = 0;
for (AsyncImageConnection *connection in _connections)
{
if (![connection isLoading])
{
if ([connection isInCache])
{
[connection start];
}
else if (count < _concurrentLoads)
{
count ++;
[connection start];
}
}
}
}
- (void)imageLoaded:(NSNotification *)notification
{
//complete connections for URL
NSURL *URL = [notification.userInfo objectForKey:AsyncImageURLKey];
for (int i = (int)[_connections count] - 1; i >= 0; i--)
{
AsyncImageConnection *connection = [_connections objectAtIndex:(NSUInteger)i];
if (connection.URL == URL || [connection.URL isEqual:URL])
{
//cancel earlier connections for same target/action
for (int j = i - 1; j >= 0; j--)
{
AsyncImageConnection *earlier = [_connections objectAtIndex:(NSUInteger)j];
if (earlier.target == connection.target &&
earlier.success == connection.success)
{
[earlier cancel];
[_connections removeObjectAtIndex:(NSUInteger)j];
i--;
}
}
//cancel connection (in case it's a duplicate)
[connection cancel];
//perform action
UIImage *image = [notification.userInfo objectForKey:AsyncImageImageKey];
#if RESIZE_IMG
// resize image before sending it over
NSData *data = UIImageJPEGRepresentation(image, 1.0);
if (data.length > MAX_IMAGE_SIZE)
{
image = [HFUtils imageWithImage:image scaledBy:MAX_IMAGE_SIZE / (float)data.length];
}
#endif
objc_msgSend(connection.target, connection.success, image, connection.URL);
//remove from queue
[_connections removeObjectAtIndex:(NSUInteger)i];
}
}
//update the queue
[self updateQueue];
}
- (void)imageFailed:(NSNotification *)notification
{
//remove connections for URL
NSURL *URL = [notification.userInfo objectForKey:AsyncImageURLKey];
for (int i = (int)[_connections count] - 1; i >= 0; i--)
{
AsyncImageConnection *connection = [_connections objectAtIndex:(NSUInteger)i];
if ([connection.URL isEqual:URL])
{
//cancel connection (in case it's a duplicate)
[connection cancel];
//perform failure action
if (connection.failure)
{
NSError *error = [notification.userInfo objectForKey:AsyncImageErrorKey];
objc_msgSend(connection.target, connection.failure, error, URL);
}
//remove from queue
[_connections removeObjectAtIndex:(NSUInteger)i];
}
}
//update the queue
[self updateQueue];
}
- (void)targetReleased:(NSNotification *)notification
{
//remove connections for URL
id target = [notification object];
for (int i = (int)[_connections count] - 1; i >= 0; i--)
{
AsyncImageConnection *connection = [_connections objectAtIndex:(NSUInteger)i];
if (connection.target == target)
{
//cancel connection
[connection cancel];
[_connections removeObjectAtIndex:(NSUInteger)i];
}
}
//update the queue
[self updateQueue];
}
- (void)loadImageWithURL:(NSURL *)URL target:(id)target success:(SEL)success failure:(SEL)failure
{
if (URL == nil)
return;
//check cache
UIImage *image = [_cache objectForKey:URL];
if (image)
{
[self cancelLoadingImagesForTarget:self action:success];
if (success) [target performSelectorOnMainThread:success withObject:image waitUntilDone:NO];
return;
}
//create new connection
AsyncImageConnection *connection = [[AsyncImageConnection alloc] initWithURL:URL
cache:_cache
target:target
success:success
failure:failure];
BOOL added = NO;
for (NSUInteger i = 0; i < [_connections count]; i++)
{
AsyncImageConnection *existingConnection = [_connections objectAtIndex:i];
if (!existingConnection.loading)
{
[_connections insertObject:connection atIndex:i];
added = YES;
break;
}
}
if (!added)
{
[_connections addObject:connection];
}
[connection release];
[self updateQueue];
}
- (void)loadImageWithURL:(NSURL *)URL target:(id)target action:(SEL)action
{
[self loadImageWithURL:URL target:target success:action failure:NULL];
}
- (void)loadImageWithURL:(NSURL *)URL
{
[self loadImageWithURL:URL target:nil success:NULL failure:NULL];
}
- (void)cancelLoadingURL:(NSURL *)URL target:(id)target action:(SEL)action
{
for (int i = (int)[_connections count] - 1; i >= 0; i--)
{
AsyncImageConnection *connection = [_connections objectAtIndex:(NSUInteger)i];
if ([connection.URL isEqual:URL] && connection.target == target && connection.success == action)
{
[connection cancel];
[_connections removeObjectAtIndex:(NSUInteger)i];
}
}
}
- (void)cancelLoadingURL:(NSURL *)URL target:(id)target
{
for (int i = (int)[_connections count] - 1; i >= 0; i--)
{
AsyncImageConnection *connection = [_connections objectAtIndex:(NSUInteger)i];
if ([connection.URL isEqual:URL] && connection.target == target)
{
[connection cancel];
[_connections removeObjectAtIndex:(NSUInteger)i];
}
}
}
- (void)cancelLoadingURL:(NSURL *)URL
{
for (int i = (int)[_connections count] - 1; i >= 0; i--)
{
AsyncImageConnection *connection = [_connections objectAtIndex:(NSUInteger)i];
if ([connection.URL isEqual:URL])
{
[connection cancel];
[_connections removeObjectAtIndex:(NSUInteger)i];
}
}
}
- (void)cancelLoadingImagesForTarget:(id)target action:(SEL)action
{
for (int i = (int)[_connections count] - 1; i >= 0; i--)
{
AsyncImageConnection *connection = [_connections objectAtIndex:(NSUInteger)i];
if (connection.target == target && connection.success == action)
{
[connection cancel];
}
}
}
- (void)cancelLoadingImagesForTarget:(id)target
{
for (int i = (int)[_connections count] - 1; i >= 0; i--)
{
AsyncImageConnection *connection = [_connections objectAtIndex:(NSUInteger)i];
if (connection.target == target)
{
[connection cancel];
}
}
}
- (NSURL *)URLForTarget:(id)target action:(SEL)action
{
//return the most recent image URL assigned to the target for the given action
//this is not neccesarily the next image that will be assigned
for (int i = (int)[_connections count] - 1; i >= 0; i--)
{
AsyncImageConnection *connection = [_connections objectAtIndex:(NSUInteger)i];
if (connection.target == target && connection.success == action)
{
return [[connection.URL ah_retain] autorelease];
}
}
return nil;
}
- (NSURL *)URLForTarget:(id)target
{
//return the most recent image URL assigned to the target
//this is not neccesarily the next image that will be assigned
for (int i = (int)[_connections count] - 1; i >= 0; i--)
{
AsyncImageConnection *connection = [_connections objectAtIndex:(NSUInteger)i];
if (connection.target == target)
{
return [[connection.URL ah_retain] autorelease];
}
}
return nil;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[_cache release];
[_connections release];
[super ah_dealloc];
}
#end
#implementation UIImageView(AsyncImageView)
- (void)setImageURL:(NSURL *)imageURL
{
[[AsyncImageLoader sharedLoader] loadImageWithURL:imageURL target:self action:#selector(setImage:)];
}
- (NSURL *)imageURL
{
return [[AsyncImageLoader sharedLoader] URLForTarget:self action:#selector(setImage:)];
}
#end
#interface AsyncImageView ()
#property (nonatomic, strong) UIActivityIndicatorView *activityView;
#end
#implementation AsyncImageView
#synthesize showActivityIndicator = _showActivityIndicator;
#synthesize activityIndicatorStyle = _activityIndicatorStyle;
#synthesize crossfadeImages = _crossfadeImages;
#synthesize crossfadeDuration = _crossfadeDuration;
#synthesize activityView = _activityView;
- (void)setUp
{
_showActivityIndicator = YES;
_activityIndicatorStyle = UIActivityIndicatorViewStyleGray;
_crossfadeImages = YES;
_crossfadeDuration = 0.4;
}
- (id)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame]))
{
[self setUp];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if ((self = [super initWithCoder:aDecoder]))
{
[self setUp];
}
return self;
}
- (void)setImageURL:(NSURL *)imageURL
{
super.imageURL = imageURL;
if (_showActivityIndicator && !self.image && imageURL)
{
if (_activityView == nil)
{
_activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:_activityIndicatorStyle];
_activityView.hidesWhenStopped = YES;
_activityView.center = CGPointMake(self.bounds.size.width / 2.0f, self.bounds.size.height / 2.0f);
_activityView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
[self addSubview:_activityView];
}
[_activityView startAnimating];
}
}
- (void)setActivityIndicatorStyle:(UIActivityIndicatorViewStyle)style
{
_activityIndicatorStyle = style;
[_activityView removeFromSuperview];
self.activityView = nil;
}
- (void)setImage:(UIImage *)image //error
{
if (_crossfadeImages)
{
//implement crossfade transition without needing to import QuartzCore
id animation = objc_msgSend(NSClassFromString(#"CATransition"), #selector(animation));
objc_msgSend(animation, #selector(setType:), #"kCATransitionFade");
objc_msgSend(animation, #selector(setDuration:), _crossfadeDuration);
objc_msgSend(self.layer, #selector(addAnimation:forKey:), animation, nil);
}
super.image = image;
[_activityView stopAnimating];
}
- (void)dealloc
{
[[AsyncImageLoader sharedLoader] cancelLoadingURL:self.imageURL target:self];
[_activityView release];
[super ah_dealloc];
}
#end

Related

How to pass data from a Swift ViewController to an Obj-C ViewController?

I am trying to pass some simple data from my ViewController in Swift to a ViewController in Objective C but I have little experience with Obj-C and I can't find any information on how to accomplish it.
Here is my Swift ViewController code:
func navigateToUpdateViewController(imageURL: URL) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "suotaViewController") as! SUOTAViewController
vc.imageURL = imageURL
self.navigationController?.pushViewController(vc, animated: true)
}
I am trying to figure out how to add the code on the Obj-C side to make this code work. I just need the imageURL property to be set. I have tried this code but I don't really understand it and it doesn't even work:
#property (nonatomic, retain) NSURL *imageURL;
Here is the Obj-C ViewController:
#define UIALERTVIEW_TAG_REBOOT 1
#import "SUOTAViewController.h"
#interface SUOTAViewController ()
#property (nonatomic, retain) NSURL *imageURL;
#end
#implementation SUOTAViewController
#synthesize blockSize;
- (void)viewDidLoad {
[super viewDidLoad];
self.textView.text = #"";
storage = [ParameterStorage getInstance];
manager = storage.manager;
[self.progressView setProgress:0];
[self.progressTextLabel setText:[NSString stringWithFormat:#"%d%%", 0]];
// Enable notifications on the status characteristic
[manager setNotifications:GenericServiceManager.SPOTA_SERVICE_CBUUID characteristicUUID:GenericServiceManager.SPOTA_SERV_STATUS_CBUUID enable:YES];
}
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[UIApplication sharedApplication].idleTimerDisabled = YES;
// Enable notifications for BLE events
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didDisconnectFromDevice:)
name:BluetoothManagerDisconnectedFromDevice
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didUpdateValueForCharacteristic:)
name:GenericServiceManagerDidReceiveValue
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didSendValueForCharacteristic:)
name:GenericServiceManagerDidSendValue
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(onBleOperationError:)
name:GenericServiceManagerWriteError
object:nil];
step = 1;
[self doStep];
}
- (void) viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[UIApplication sharedApplication].idleTimerDisabled = NO;
// Disable notifications for BLE events
[[NSNotificationCenter defaultCenter] removeObserver:self name:BluetoothManagerDisconnectedFromDevice object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:GenericServiceManagerDidReceiveValue object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:GenericServiceManagerDidSendValue object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:GenericServiceManagerWriteError object:nil];
}
- (void) didDisconnectFromDevice: (NSNotification*)notification {
if (step != 8) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:step != 7 ? #"Upload Failed" : #"Device Disconnected"
message:#"The connection to the remote device was lost."
delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
}
- (void) didUpdateValueForCharacteristic: (NSNotification*)notification {
CBCharacteristic *characteristic = (CBCharacteristic*) notification.object;
if ([characteristic.UUID isEqual:GenericServiceManager.SPOTA_SERV_STATUS_CBUUID]) {
char value;
[characteristic.value getBytes:&value length:sizeof(char)];
NSString *message = [self getErrorMessage:value];
[self debug:message UILog:(value != SPOTAR_CMP_OK)];
if (expectedValue != 0) {
// Check if value equals the expected value
if (value == expectedValue) {
// If so, continue with the next step
step = nextStep;
expectedValue = 0; // Reset
[self doStep];
} else {
// Else display an error message
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error" message:message delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
expectedValue = 0; // Reset
}
}
}
}
- (void) didSendValueForCharacteristic: (NSNotification*)notification {
if (step && step != 7) {
[self doStep];
}
}
- (void) onBleOperationError: (NSNotification*)notification {
[self debug:[NSString stringWithFormat:#"Error in BLE operation on characteristic %#", ((CBCharacteristic*)notification.object).UUID] UILog:YES];
if (step != 8) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Upload Failed"
message:#"The firmware upload procedure encountered an error."
delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
}
- (void) doStep {
[self debug:[NSString stringWithFormat:#"*** Next step: %d", step] UILog:NO];
switch (step) {
case 1: {
// Step 1: Set memory type
step = 0;
expectedValue = 0x10;
nextStep = 2;
uploadStart = [NSDate date];
uint32_t _memDevData = (self.memoryType << 24) | self.memoryBank;
[self debug:[NSString stringWithFormat:#"Set SPOTA_MEM_DEV: %#010x", _memDevData] UILog:YES];
NSData *memDevData = [NSData dataWithBytes:&_memDevData length:sizeof(uint32_t)];
[manager writeValue:GenericServiceManager.SPOTA_SERVICE_CBUUID characteristicUUID:GenericServiceManager.SPOTA_MEM_DEV_CBUUID data:memDevData];
break;
}
case 2: {
// Step 2: Set memory params
uint32_t _memInfoData = 0;
if (self.memoryType == MEM_TYPE_SUOTA_SPI) {
_memInfoData = (self.spiMISOGPIO << 24) | (self.spiMOSIGPIO << 16) | (self.spiCSGPIO << 8) | self.spiSCKGPIO;
} else if (self.memoryType == MEM_TYPE_SUOTA_I2C) {
_memInfoData = (self.i2cAddress << 16) | (self.i2cSCLGPIO << 8) | self.i2cSDAGPIO;
}
[self debug:[NSString stringWithFormat:#"Set SPOTA_GPIO_MAP: %#010x", _memInfoData] UILog:YES];
NSData *memInfoData = [NSData dataWithBytes:&_memInfoData length:sizeof(uint32_t)];
step = 3;
[manager writeValue:GenericServiceManager.SPOTA_SERVICE_CBUUID characteristicUUID:GenericServiceManager.SPOTA_GPIO_MAP_CBUUID data:memInfoData];
break;
}
case 3: {
// Load patch data
[self debug:[NSString stringWithFormat:#"Loading data from %#", storage.file_url.absoluteString.stringByRemovingPercentEncoding] UILog:YES];
fileData = [[NSData dataWithContentsOfURL:storage.file_url] mutableCopy];
[self appendChecksum];
[self debug:[NSString stringWithFormat:#"Upload size: %d bytes", (int) [fileData length]] UILog:YES];
// Step 3: Set patch length
chunkSize = MIN(manager.suotaPatchDataSize, manager.suotaMtu - 3);
blockSize = MAX(blockSize, chunkSize);
if (blockSize > fileData.length) {
blockSize = fileData.length;
if (chunkSize > blockSize)
chunkSize = blockSize;
}
blockStartByte = 0;
[self debug:[NSString stringWithFormat:#"Chunk size: %d bytes", chunkSize] UILog:YES];
step = 4;
[self doStep];
break;
}
case 4: {
// Set patch length
[self debug:[NSString stringWithFormat:#"Set SPOTA_PATCH_LEN: %d", blockSize] UILog:YES];
NSData *patchLengthData = [NSData dataWithBytes:&blockSize length:sizeof(uint16_t)];
step = 5;
[manager writeValue:GenericServiceManager.SPOTA_SERVICE_CBUUID characteristicUUID:GenericServiceManager.SPOTA_PATCH_LEN_CBUUID data:patchLengthData];
break;
}
case 5: {
// Send current block in chunks of 20 bytes
if (blockStartByte == 0)
[self debug:#"Upload procedure started" UILog:YES];
step = 0;
expectedValue = 0x02;
nextStep = 5;
int dataLength = (int) [fileData length];
int chunkStartByte = 0;
while (chunkStartByte < blockSize) {
// Check if we have less than current block-size bytes remaining
int bytesRemaining = blockSize - chunkStartByte;
int currChunkSize = bytesRemaining >= chunkSize ? chunkSize : bytesRemaining;
[self debug:[NSString stringWithFormat:#"Sending bytes %d to %d (%d/%d) of %d", blockStartByte + chunkStartByte + 1, blockStartByte + chunkStartByte + currChunkSize, chunkStartByte + currChunkSize, blockSize, dataLength] UILog:NO];
double progress = (double)(blockStartByte + chunkStartByte + currChunkSize) / (double)dataLength;
[self.progressView setProgress:progress];
[self.progressTextLabel setText:[NSString stringWithFormat:#"%d%%", (int)(100 * progress)]];
// Step 4: Send next n bytes of the patch
char bytes[currChunkSize];
[fileData getBytes:bytes range:NSMakeRange(blockStartByte + chunkStartByte, currChunkSize)];
NSData *byteData = [NSData dataWithBytes:bytes length:currChunkSize];
// On to the chunk
chunkStartByte += currChunkSize;
// Check if we are passing the current block
if (chunkStartByte >= blockSize) {
// Prepare for next block
blockStartByte += blockSize;
int bytesRemaining = dataLength - blockStartByte;
if (bytesRemaining == 0) {
nextStep = 6;
} else if (bytesRemaining < blockSize) {
blockSize = bytesRemaining;
nextStep = 4; // Back to step 4, setting the patch length
}
}
[manager writeValueWithoutResponse:GenericServiceManager.SPOTA_SERVICE_CBUUID characteristicUUID:GenericServiceManager.SPOTA_PATCH_DATA_CBUUID data:byteData];
}
break;
}
case 6: {
// Send SUOTA END command
step = 0;
expectedValue = 0x02;
nextStep = 7;
uint32_t suotaEnd = 0xFE000000;
[self debug:[NSString stringWithFormat:#"Send SUOTA END command: %#010x", suotaEnd] UILog:YES];
NSData *suotaEndData = [NSData dataWithBytes:&suotaEnd length:sizeof(uint32_t)];
[manager writeValue:GenericServiceManager.SPOTA_SERVICE_CBUUID characteristicUUID:GenericServiceManager.SPOTA_MEM_DEV_CBUUID data:suotaEndData];
break;
}
case 7: {
[self debug:#"Upload completed" UILog:YES];
NSTimeInterval elapsed = [[NSDate date] timeIntervalSinceDate:uploadStart];
[self debug:[NSString stringWithFormat:#"Elapsed time: %.3f", elapsed] UILog:YES];
// Wait for user to confirm reboot
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Device has been updated" message:#"Do you wish to reboot the device?" delegate:self cancelButtonTitle:#"No" otherButtonTitles:#"Yes, reboot", nil];
[alert setTag:UIALERTVIEW_TAG_REBOOT];
[alert show];
break;
}
case 8: {
// Go back to overview of devices
[self dismissViewControllerAnimated:YES completion:nil];
break;
}
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (alertView.tag == UIALERTVIEW_TAG_REBOOT) {
if (buttonIndex != alertView.cancelButtonIndex) {
// Send reboot signal to device
step = 8;
uint32_t suotaReboot = 0xFD000000;
[self debug:[NSString stringWithFormat:#"Send SUOTA REBOOT command: %#010x", suotaReboot] UILog:YES];
NSData *suotaRebootData = [NSData dataWithBytes:&suotaReboot length:sizeof(uint32_t)];
[manager writeValue:GenericServiceManager.SPOTA_SERVICE_CBUUID characteristicUUID:GenericServiceManager.SPOTA_MEM_DEV_CBUUID data:suotaRebootData];
}
}
}
- (void) debug:(NSString*)message UILog:(BOOL)uiLog {
if (uiLog) {
self.textView.text = [self.textView.text stringByAppendingString:[NSString stringWithFormat:#"\n%#", message]];
[self.textView scrollRangeToVisible:NSMakeRange([self.textView.text length], 0)];
}
NSLog(#"%#", message);
}
- (void) appendChecksum {
uint8_t crc_code = 0;
const char *bytes = [fileData bytes];
for (int i = 0; i < [fileData length]; i++) {
crc_code ^= bytes[i];
}
[self debug:[NSString stringWithFormat:#"Checksum for file: %#4x", crc_code] UILog:YES];
[fileData appendBytes:&crc_code length:sizeof(uint8_t)];
}
#end
First, your Obj-C class is setting *imageURL as a private property. You haven't exposed it for use elsewhere.
So, let's start simple...
SUOTAViewController.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
#interface SUOTAViewController : UIViewController
#property (strong, nonatomic) NSURL *imageURL;
#end
NS_ASSUME_NONNULL_END
SUOTAViewController.m
#import "SUOTAViewController.h"
#interface SUOTAViewController ()
#end
#implementation SUOTAViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"Image URL: %#", _imageURL);
}
#end
YourProject-Bridging-Header.h
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "SUOTAViewController.h"
Swift View Controller
guard let imageURL = URL(string: "https://i.stack.imgur.com/Cv0gs.png") else { return }
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let vc = storyboard.instantiateViewController(withIdentifier: "suotaViewController") as? SUOTAViewController {
vc.imageURL = imageURL
self.navigationController?.pushViewController(vc, animated: true)
}
The Obj-C class above will output the URL to the debug console.
You can do whatever you want with it after that.
This is the image that URL is pointing to:

How to debug "unrecognized selector sent to instance"

I want to check if the user has an open basket if so send them to the menu if not then send send them to my open basket view but i m getting an error.
So my question is how to get rid of this problem ? and is my logic right ?
'NSInvalidArgumentException', reason: '-[Merchant merchantId]: unrecognized selector sent to instance 0x7fad19529490'.
i m using this method to check for open baskets when the button addToOrderButtonTapped is press in the menuview
[[OrderManager sharedManager]getBasketsForMerchant:merchant success:^(NSArray *baskets) {
for (Basket *basket in baskets){
if ([basket.status isEqualToString:kBasketStatusOpen]) {
[self.openBaskets addObject:basket];
}
}if (self.openBaskets.count > 0){
self.openBaskets = self.openBaskets;
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:kSegueMenu sender:self];
});
}
else {
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:KSegueOpenBasket sender:self];
});
}
} failure:^(NSError *error, NSHTTPURLResponse *response) {
dispatch_async(dispatch_get_main_queue(), ^{
NSString *localizedString = NSLocalizedString(#"Order.ErrorLoadingOpenOrders", "Get error message");
[self showMessage:localizedString withTitle:MessageTypeError];
[MBProgressHUD hideAllHUDsForView:self.view animated:YES];
});
}];
The menuview
//
// MenuItemViewController.m
// BaseApp
//
#import "MenuItemViewController.h"
#import "RoundedButton.h"
#import "MenuOptionCell.h"
#import "MenuItem.h"
#import "MenuOptionButton.h"
#import "MenuChoice.h"
#import "OrderManager.h"
#import "TypeOfChoiceCell.h"
#import "MenuOption.h"
#import "OrderPricingTableViewCell.h"
#import "RKManagedObjectStore.h"
#import "NSManagedObjectContext+RKAdditions.h"
#import "MerchantManager.h"
#import "Merchant.h"
#import "OrdersViewController.h"
#import "MenuItem.h"
#import "MenuViewController.h"
#import "OrderConfirmationViewController.h"
#import "OrderManager.h"
#import "APIClient.h"
#import "MenuManager.h"
#import "DiscoverViewController.h"
#import "DiscoverCollectionViewCell.h"
#import "MerchantManager.h"
#import "MenuViewController.h"
#import "MenuManager.h"
#import "MerchantDetailsViewController.h"
#import "OpenOrdersViewController.h"
typedef NS_ENUM(NSUInteger, MenuOptionsSection) {
MenuOptionsSectionRequired = 0,
MenuOptionsSectionOptional = 1
};
static NSString *const OpenBasketsSegue = #"OpenBaskets";
static NSString *const kSegueMenu = #"ShowMenu";
static NSString *const KSegueOpenBasket = #"OpenBaskets";
#interface MenuItemViewController () <UITableViewDelegate, UITableViewDataSource>
#property (nonatomic, weak) IBOutlet UILabel *menuItemName;
#property (nonatomic, weak) IBOutlet UILabel *quantityLabel;
#property (nonatomic, weak) IBOutlet UILabel *menuItemPrice;
#property (nonatomic, weak) IBOutlet UILabel *subTotalLabel;
#property (nonatomic, weak) IBOutlet UITextView *menuItemDescription;
#property (nonatomic, weak) IBOutlet RoundedButton *addToOrderButton;
#property (nonatomic, weak) IBOutlet UITableView *tableView;
#property (nonatomic, weak) IBOutlet UIView *cartView;
#property (nonatomic, weak) IBOutlet UIButton *subtractButton;
#property (nonatomic) NSDecimalNumber *temporarySubtotal;
#property (nonatomic, strong) NSMutableArray<MenuOption *> *requiredChoices;
#property (nonatomic, strong) NSMutableArray<MenuOption *> *optionalChoices;
#property (nonatomic, strong) NSMutableArray<NSMutableArray *> *optionChoicesSection;
#property (nonatomic, strong) NSMutableArray<NSDictionary *> *options;
#property (nonatomic, strong) NSMutableArray <Basket *>*openBaskets;
#property (nonatomic) BOOL launchViewFirstTime;
#end
#implementation MenuItemViewController
#pragma - Lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = #"Menu Item";
self.menuItemName.text = self.menuCategory.selectedBasketLine.menuItem.name;
self.menuItemPrice.text = [NSString stringWithFormat:#"%#", [Basket formattedCurrencyStringForAmount:self.menuCategory.selectedBasketLine.menuItem.price]];
self.quantityLabel.text = self.menuCategory.selectedBasketLine.quantity.stringValue;
self.temporarySubtotal = [self calculateTemporarySubtotal:[OrderManager sharedManager].currentBasket.subtotal menuItemPrice:self.menuCategory.selectedBasketLine.menuItem.price];
[self setSubtotalText:self.temporarySubtotal];
self.menuItemDescription.text = self.menuCategory.selectedBasketLine.menuItem.menuItemDescription;
self.subtractButton.alpha = 0.65;
self.requiredChoices = [[NSMutableArray alloc] init];
self.optionalChoices = [[NSMutableArray alloc] init];
self.optionChoicesSection = [[NSMutableArray alloc] init];
self.options = [[NSMutableArray alloc] init];
[self initializeChoiceArrays];
self.tableView.delegate = self;
self.tableView.dataSource = self;
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.launchViewFirstTime = YES;
if (self.optionChoicesSection.count > 0) {
[self.tableView reloadData];
} else {
self.tableView.hidden = YES;
}
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.launchViewFirstTime = NO;
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
for (MenuOption *menuOption in self.requiredChoices) {
[menuOption resetNumberOfChoicesSelected];
}
for (MenuOption *menuOption in self.optionalChoices) {
[menuOption resetNumberOfChoicesSelected];
}
self.menuCategory = nil;
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[self.menuItemDescription setContentOffset:CGPointZero animated:YES];
}
#pragma - IBActions
- (IBAction)addButtonTapped:(id)sender {
NSInteger count = self.quantityLabel.text.integerValue;
count++;
if (count > 1) {
self.subtractButton.alpha = 1;
}
NSDecimalNumber *newSubTotal = [self.temporarySubtotal decimalNumberByAdding:self.menuCategory.selectedBasketLine.menuItem.price];
[self modifyCurrentBasketSubtotal:newSubTotal quantity:count];
}
- (IBAction)subtractButtonTapped:(id)sender {
NSInteger count = self.quantityLabel.text.integerValue;
if (count > 1) {
count--;
NSDecimalNumber *newSubTotal = [self.temporarySubtotal decimalNumberBySubtracting:self.menuCategory.selectedBasketLine.menuItem.price];
[self modifyCurrentBasketSubtotal:newSubTotal quantity:count];
if (count == 1) {
self.subtractButton.alpha = 0.65;
}
}
}
- (IBAction)addToOrderButtonTapped:(id)sender {
MenuOption *menuOption;
Merchant *merchant = [[Merchant alloc]init];
// First check if there are any missing required options that have to be selected
if ((menuOption = [self checkMissingRequiredOptionsHaveBeenSelected])) {
NSString *localizedString = NSLocalizedString(#"AddMenuItem.RequiredChoicesNotSelected", #"Get string for error");
NSString *formattedString = [NSString stringWithFormat:localizedString, menuOption.name];
[self showMessage:formattedString withTitle:MessageTypeError];
return;
}
// Now check if the minimum and maximum choice seletion have been met for the menu options
if ((menuOption = [self validateMinMaxForMenuOptionsHaveBeenMet])) {
NSString *localizedString = NSLocalizedString(#"AddMenuItem.MinMaxNotFulfilled", #"Get string for error");
NSString *formattedString = [NSString stringWithFormat:localizedString, menuOption.name];
[self showMessage:formattedString withTitle:MessageTypeError];
return;
}
// Add the menu item to the basket
if (self.menuItemAddedBlock) {
self.menuItemAddedBlock(self, self.menuCategory);
// [self dismissViewControllerAnimated:YES completion:nil];
//checking for open basket here
[[OrderManager sharedManager]getBasketsForMerchant:merchant success:^(NSArray *baskets) {
for (Basket *basket in baskets){
if ([basket.status isEqualToString:kBasketStatusOpen]) {
[self.openBaskets addObject:basket];
}
}if (self.openBaskets.count > 0){
self.openBaskets = self.openBaskets;
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:kSegueMenu sender:self];
});
}
else {
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:KSegueOpenBasket sender:self];
});
}
} failure:^(NSError *error, NSHTTPURLResponse *response) {
dispatch_async(dispatch_get_main_queue(), ^{
NSString *localizedString = NSLocalizedString(#"Order.ErrorLoadingOpenOrders", "Get error message");
[self showMessage:localizedString withTitle:MessageTypeError];
[MBProgressHUD hideAllHUDsForView:self.view animated:YES];
});
}];
}
}
- (IBAction)cancelButtonTapped:(UIBarButtonItem *)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
#pragma - UITableViewDelegate, UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.optionChoicesSection.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.optionChoicesSection[section].count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MenuOptionCell *cell = (MenuOptionCell *)[tableView dequeueReusableCellWithIdentifier:[MenuOptionCell reuseIdentifier]];
cell.menuOption = self.optionChoicesSection[indexPath.section][indexPath.row];
cell.menuOptionCellButtonPressedBlock = ^(MenuOptionButton *button, MenuOption *option, MenuChoice *choice) {
[self adjustSelectedOptions:option choice:choice indexPath:indexPath];
};
cell.menuOptionCellDefaultOptionDetectedBlock = ^(MenuOptionButton *button, MenuOption *option, MenuChoice *choice) {
[self adjustSelectedOptions:option choice:choice indexPath:indexPath];
};
cell.menuOptionCellDeselectedBlock = ^(MenuOptionButton *button, MenuOption *option, MenuChoice *choice) {
[self adjustSelectedOptions:option choice:choice indexPath:indexPath];
};
[cell configureCell:self.launchViewFirstTime];
return cell;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
TypeOfChoiceCell *cell = (TypeOfChoiceCell *)[tableView dequeueReusableCellWithIdentifier:[TypeOfChoiceCell reuseIdentifier]];
switch ((MenuOptionsSection)section) {
case MenuOptionsSectionRequired:
if (self.requiredChoices.count > 0) {
cell.title = NSLocalizedString(#"AddMenuItem.RequiredChoiceText", #"Get string for title");
return cell;
} else if (self.optionalChoices.count > 0) {
cell.title = NSLocalizedString(#"AddMenuItem.OptionalChoiceText", #"get string for title");
return cell;
}
case MenuOptionsSectionOptional:
if (self.optionalChoices.count > 0) {
cell.title = NSLocalizedString(#"AddMenuItem.OptionalChoiceText", #"Get string for title");
return cell;
}
}
return nil;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
MenuOption *option = self.optionChoicesSection[indexPath.section][indexPath.row];
return [MenuOptionCell heightForMenuOption:option];
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return [TypeOfChoiceCell height];
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return 0.01f;
}
#pragma - Helpers
- (void)setSubtotalText:(NSDecimalNumber *)subtotal {
if (!subtotal) {
self.subTotalLabel.text = NSLocalizedString(#"AddMenuItem.SubtotalDefault", #"Get string for subtotal");
} else {
NSString *localizedString = NSLocalizedString(#"AddMenuItem.SubtotalFormatted", #"Get string for subtotal");
self.subTotalLabel.text = [NSString stringWithFormat:localizedString, [Basket formattedCurrencyStringForAmount:subtotal]];
}
}
- (void)modifyCurrentBasketSubtotal:(NSDecimalNumber *)subtotal quantity:(NSInteger)quantity {
self.menuCategory.selectedBasketLine.quantity = [NSNumber numberWithInteger:quantity];
self.menuCategory.selectedBasketLine.subtotal = subtotal;
self.temporarySubtotal = subtotal;
[self setSubtotalText:subtotal];
self.quantityLabel.text = self.menuCategory.selectedBasketLine.quantity.stringValue;
}
- (NSDecimalNumber *)calculateTemporarySubtotal:(NSDecimalNumber *)orderManagerSubTotal menuItemPrice:(NSDecimalNumber *)menuItemPrice {
if (orderManagerSubTotal == 0) {
return menuItemPrice;
} else {
return [orderManagerSubTotal decimalNumberByAdding:menuItemPrice];
}
}
- (MenuOption *)checkMissingRequiredOptionsHaveBeenSelected {
for (MenuOption *menuOption in self.requiredChoices) {
if (!menuOption.selected) {
return menuOption;
}
}
return nil;
}
- (MenuOption *)validateMinMaxForMenuOptionsHaveBeenMet {
for (MenuOption *menuOption in self.requiredChoices) {
if ([menuOption validateIndividualMinMaxForMenuOption]) {
return menuOption;
}
}
for (MenuOption *menuOption in self.optionalChoices) {
if (menuOption.selected) {
if ([menuOption validateIndividualMinMaxForMenuOption]) {
return menuOption;
}
}
}
return nil;
}
- (void)initializeChoiceArrays {
NSArray<MenuOption *> *menuOptions = [self.menuCategory.selectedBasketLine.menuItem.menuOptions allObjects];
for (MenuOption *menuOption in menuOptions) {
if (menuOption.minimumChoices == nil) {
menuOption.minimumChoices = [NSNumber numberWithInt:0];
}
if (menuOption.maximumChoices == nil) {
menuOption.maximumChoices = [NSNumber numberWithInt:0];
}
// For now make an optional choice required if minimumChoices > 0
if (menuOption.isRequired || [menuOption.minimumChoices intValue] > 0) {
menuOption.isRequired = YES;
[self.requiredChoices addObject:menuOption];
} else {
[self.optionalChoices addObject:menuOption];
}
}
if (self.requiredChoices.count > 0) {
[self.optionChoicesSection addObject:self.requiredChoices];
}
if (self.optionalChoices.count > 0) {
[self.optionChoicesSection addObject:self.optionalChoices];
}
}
- (void)adjustSelectedOptions:(MenuOption *)option choice:(MenuChoice *)choice indexPath:(NSIndexPath *)indexPath {
self.menuCategory.selectedBasketLine.subtotal = self.menuCategory.selectedBasketLine.menuItem.price;
if (option.selected && option.menuChoices.count == 0) {
[self.options addObject:#{kOption: option.menuOptionId ?: #"", kChoice: #""}];
if (option.price) {
self.temporarySubtotal = [self.temporarySubtotal decimalNumberByAdding:option.price];
}
if (option.isRequired) {
self.requiredChoices[indexPath.row].selected = option.selected;
self.requiredChoices[indexPath.row].numberOfChoicesSelected = option.numberOfChoicesSelected;
} else {
self.optionalChoices[indexPath.row].selected = option.selected;
self.optionalChoices[indexPath.row].numberOfChoicesSelected = option.numberOfChoicesSelected;
}
} else {
if (option.menuChoices.count == 0) {
[self.options removeObject:#{kOption: option.menuOptionId ?: #"", kChoice: #""}];
if (option.price) {
self.temporarySubtotal = [self.temporarySubtotal decimalNumberBySubtracting:option.price];
}
if (option.isRequired) {
self.requiredChoices[indexPath.row].selected = option.selected;
self.requiredChoices[indexPath.row].numberOfChoicesSelected = option.numberOfChoicesSelected;
} else {
self.optionalChoices[indexPath.row].selected = option.selected;
self.optionalChoices[indexPath.row].numberOfChoicesSelected = option.numberOfChoicesSelected;
}
}
}
if (choice.selected && option.menuChoices.count > 0) {
[self.options addObject:#{kOption: choice.menuOption.menuOptionId ?: #"", kChoice: choice.menuChoiceId ?: #""}];
if (choice.price) {
self.temporarySubtotal = [self.temporarySubtotal decimalNumberByAdding:choice.price];
}
if (option.isRequired) {
self.requiredChoices[indexPath.row].selected = choice.selected;
self.requiredChoices[indexPath.row].numberOfChoicesSelected = option.numberOfChoicesSelected;
} else {
self.optionalChoices[indexPath.row].selected = choice.selected;
self.optionalChoices[indexPath.row].numberOfChoicesSelected = option.numberOfChoicesSelected;
}
} else {
if (option.menuChoices.count > 0) {
[self.options removeObject:#{kOption: choice.menuOption.menuOptionId ?: #"", kChoice: choice.menuChoiceId ?: #""}];
if (choice.price) {
self.temporarySubtotal = [self.temporarySubtotal decimalNumberBySubtracting:choice.price];
}
if (option.isRequired) {
if ([option.numberOfChoicesSelected intValue] == 0) {
self.requiredChoices[indexPath.row].selected = option.selected;
} else {
self.requiredChoices[indexPath.row].selected = !choice.selected;
}
self.requiredChoices[indexPath.row].numberOfChoicesSelected = option.numberOfChoicesSelected;
} else {
self.optionalChoices[indexPath.row].selected = choice.selected;
self.optionalChoices[indexPath.row].numberOfChoicesSelected = option.numberOfChoicesSelected;
}
}
}
[self setSubtotalText:self.temporarySubtotal];
self.menuCategory.selectedBasketLine.attributes = self.options;
}
#end
This is the line of code thats giving me the error
+ (void)getBasketsForMerchant:(Merchant *)merchant success:(void (^)(NSArray *basket))success failure:(void (^)(NSError *, NSHTTPURLResponse *))failure {
NSMutableDictionary* params = #{#"expand": #"merchant"}.mutableCopy;
if (merchant) {
params[#"merchant"] = merchant.merchantId;
}
[[RKObjectManager sharedManager] getObjectsAtPath:kOrdersEndpoint parameters:params success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult){
NSArray* items = mappingResult.array;
if (success) {
success(items);
}
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
if (failure) {
failure(error, operation.HTTPRequestOperation.response);
} else {
_defaultFailureBlock(operation, error);
}
}];
}
This error:
'NSInvalidArgumentException', reason: '-[Merchant merchantId]: unrecognized selector sent to instance 0x7fad19529490'.
Means that you have an object at location 0x7fad19529490 and you tried to call "merchantId" on it. That object does not respond to merchantId.
So, look very carefully at the definition of Merchant. Did you get the spelling of merchantId right in fieldMappings? Is it merchantID with a capital D?
If you are sure that merchant has a property named merchantId exactly, then, the next likely thing is that the object at 0x7fad19529490 is not a Merchant.
The easiest thing to do is to add an exception breakpoint (use the +) at the bottom of the breakpoint navigator. When this exception happens, grab the pointer address from the error (it might be different each time) and see what it is in the debugger. To do that, at the (lldb) prompt, type:
po (NSObject*)(0x7fad19529490)
but use the address from the error. If it's a Merchant, I expect it to say something like:
<Merchant: 0x7fad19529490>
Or, if you have overridden description, it will be the output of that.

Signal Sigabrt Error

I cloned this project from Github and when I build and ran it it showed up this Sigabrt error. The console says,
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in may also be helpful.
MoltinSwiftExample(10351,0x700000323000) malloc: * error for object 0x7ff288d71cc0: pointer being freed was not allocated
* set a breakpoint in malloc_error_break to debug
Here is my code.
#import "SDWebImageDownloaderOperation.h"
#import "SDWebImageDecoder.h"
#import "UIImage+MultiFormat.h"
#import <ImageIO/ImageIO.h>
#import "SDWebImageManager.h"
NSString *const SDWebImageDownloadStartNotification = #"SDWebImageDownloadStartNotification";
NSString *const SDWebImageDownloadReceiveResponseNotification = #"SDWebImageDownloadReceiveResponseNotification";
NSString *const SDWebImageDownloadStopNotification = #"SDWebImageDownloadStopNotification";
NSString *const SDWebImageDownloadFinishNotification = #"SDWebImageDownloadFinishNotification";
#interface SDWebImageDownloaderOperation () <NSURLConnectionDataDelegate>
#property (copy, nonatomic) SDWebImageDownloaderProgressBlock progressBlock;
#property (copy, nonatomic) SDWebImageDownloaderCompletedBlock completedBlock;
#property (copy, nonatomic) SDWebImageNoParamsBlock cancelBlock;
#property (assign, nonatomic, getter = isExecuting) BOOL executing;
#property (assign, nonatomic, getter = isFinished) BOOL finished;
#property (strong, nonatomic) NSMutableData *imageData;
#property (strong, nonatomic) NSURLConnection *connection;
#property (strong, atomic) NSThread *thread;
#if TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0
#property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundTaskId;
#endif
#end
#implementation SDWebImageDownloaderOperation {
size_t width, height;
UIImageOrientation orientation;
BOOL responseFromCached;
}
#synthesize executing = _executing;
#synthesize finished = _finished;
- (id)initWithRequest:(NSURLRequest *)request
options:(SDWebImageDownloaderOptions)options
progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageDownloaderCompletedBlock)completedBlock
cancelled:(SDWebImageNoParamsBlock)cancelBlock {
if ((self = [super init])) {
_request = request;
_shouldDecompressImages = YES;
_shouldUseCredentialStorage = YES;
_options = options;
_progressBlock = [progressBlock copy];
_completedBlock = [completedBlock copy];
_cancelBlock = [cancelBlock copy];
_executing = NO;
_finished = NO;
_expectedSize = 0;
responseFromCached = YES; // Initially wrong until `connection:willCacheResponse:` is called or not called
}
return self;
}
- (void)start {
#synchronized (self) {
if (self.isCancelled) {
self.finished = YES;
[self reset];
return;
}
#if TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0
Class UIApplicationClass = NSClassFromString(#"UIApplication");
BOOL hasApplication = UIApplicationClass && [UIApplicationClass respondsToSelector:#selector(sharedApplication)];
if (hasApplication && [self shouldContinueWhenAppEntersBackground]) {
__weak __typeof__ (self) wself = self;
UIApplication * app = [UIApplicationClass performSelector:#selector(sharedApplication)];
self.backgroundTaskId = [app beginBackgroundTaskWithExpirationHandler:^{
__strong __typeof (wself) sself = wself;
if (sself) {
[sself cancel];
[app endBackgroundTask:sself.backgroundTaskId];
sself.backgroundTaskId = UIBackgroundTaskInvalid;
}
}];
}
#endif
self.executing = YES;
self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];
self.thread = [NSThread currentThread];
}
[self.connection start];
if (self.connection) {
if (self.progressBlock) {
self.progressBlock(0, NSURLResponseUnknownLength);
}
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStartNotification object:self];
});
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_5_1) {
// Make sure to run the runloop in our background thread so it can process downloaded data
// Note: we use a timeout to work around an issue with NSURLConnection cancel under iOS 5
// not waking up the runloop, leading to dead threads (see https://github.com/rs/SDWebImage/issues/466)
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, false);
}
else {
CFRunLoopRun();
}
if (!self.isFinished) {
[self.connection cancel];
[self connection:self.connection didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorTimedOut userInfo:#{NSURLErrorFailingURLErrorKey : self.request.URL}]];
}
}
else {
if (self.completedBlock) {
self.completedBlock(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:0 userInfo:#{NSLocalizedDescriptionKey : #"Connection can't be initialized"}], YES);
}
}
#if TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0
Class UIApplicationClass = NSClassFromString(#"UIApplication");
if(!UIApplicationClass || ![UIApplicationClass respondsToSelector:#selector(sharedApplication)]) {
return;
}
if (self.backgroundTaskId != UIBackgroundTaskInvalid) {
UIApplication * app = [UIApplication performSelector:#selector(sharedApplication)];
[app endBackgroundTask:self.backgroundTaskId];
self.backgroundTaskId = UIBackgroundTaskInvalid;
}
#endif
}
- (void)cancel {
#synchronized (self) {
if (self.thread) {
[self performSelector:#selector(cancelInternalAndStop) onThread:self.thread withObject:nil waitUntilDone:NO];
}
else {
[self cancelInternal];
}
}
}
- (void)cancelInternalAndStop {
if (self.isFinished) return;
[self cancelInternal];
CFRunLoopStop(CFRunLoopGetCurrent());
}
- (void)cancelInternal {
if (self.isFinished) return;
[super cancel];
if (self.cancelBlock) self.cancelBlock();
if (self.connection) {
[self.connection cancel];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:self];
});
// As we cancelled the connection, its callback won't be called and thus won't
// maintain the isFinished and isExecuting flags.
if (self.isExecuting) self.executing = NO;
if (!self.isFinished) self.finished = YES;
}
[self reset];
}
- (void)done {
self.finished = YES;
self.executing = NO;
[self reset];
}
- (void)reset {
self.cancelBlock = nil;
self.completedBlock = nil;
self.progressBlock = nil;
self.connection = nil;
self.imageData = nil;
self.thread = nil;
}
- (void)setFinished:(BOOL)finished {
[self willChangeValueForKey:#"isFinished"];
_finished = finished;
[self didChangeValueForKey:#"isFinished"];
}
- (void)setExecuting:(BOOL)executing {
[self willChangeValueForKey:#"isExecuting"];
_executing = executing;
[self didChangeValueForKey:#"isExecuting"];
}
- (BOOL)isConcurrent {
return YES;
}
#pragma mark NSURLConnection (delegate)
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
//'304 Not Modified' is an exceptional one
if (![response respondsToSelector:#selector(statusCode)] || ([((NSHTTPURLResponse *)response) statusCode] < 400 && [((NSHTTPURLResponse *)response) statusCode] != 304)) {
NSInteger expected = response.expectedContentLength > 0 ? (NSInteger)response.expectedContentLength : 0;
self.expectedSize = expected;
if (self.progressBlock) {
self.progressBlock(0, expected);
}
self.imageData = [[NSMutableData alloc] initWithCapacity:expected];
self.response = response;
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadReceiveResponseNotification object:self];
});
}
else {
NSUInteger code = [((NSHTTPURLResponse *)response) statusCode];
//This is the case when server returns '304 Not Modified'. It means that remote image is not changed.
//In case of 304 we need just cancel the operation and return cached image from the cache.
if (code == 304) {
[self cancelInternal];
} else {
[self.connection cancel];
}
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:self];
});
if (self.completedBlock) {
self.completedBlock(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:[((NSHTTPURLResponse *)response) statusCode] userInfo:nil], YES);
}
CFRunLoopStop(CFRunLoopGetCurrent());
[self done];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.imageData appendData:data];
if ((self.options & SDWebImageDownloaderProgressiveDownload) && self.expectedSize > 0 && self.completedBlock) {
// The following code is from http://www.cocoaintheshell.com/2011/05/progressive-images-download-imageio/
// Thanks to the author #Nyx0uf
// Get the total bytes downloaded
const NSInteger totalSize = self.imageData.length;
// Update the data source, we must pass ALL the data, not just the new bytes
CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)self.imageData, NULL);
if (width + height == 0) {
CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL);
if (properties) {
NSInteger orientationValue = -1;
CFTypeRef val = CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight);
if (val) CFNumberGetValue(val, kCFNumberLongType, &height);
val = CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth);
if (val) CFNumberGetValue(val, kCFNumberLongType, &width);
val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation);
if (val) CFNumberGetValue(val, kCFNumberNSIntegerType, &orientationValue);
CFRelease(properties);
// When we draw to Core Graphics, we lose orientation information,
// which means the image below born of initWithCGIImage will be
// oriented incorrectly sometimes. (Unlike the image born of initWithData
// in connectionDidFinishLoading.) So save it here and pass it on later.
orientation = [[self class] orientationFromPropertyValue:(orientationValue == -1 ? 1 : orientationValue)];
}
}
if (width + height > 0 && totalSize < self.expectedSize) {
// Create the image
CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL);
#ifdef TARGET_OS_IPHONE
// Workaround for iOS anamorphic image
if (partialImageRef) {
const size_t partialHeight = CGImageGetHeight(partialImageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef bmContext = CGBitmapContextCreate(NULL, width, height, 8, width * 4, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(colorSpace);
if (bmContext) {
CGContextDrawImage(bmContext, (CGRect){.origin.x = 0.0f, .origin.y = 0.0f, .size.width = width, .size.height = partialHeight}, partialImageRef);
CGImageRelease(partialImageRef);
partialImageRef = CGBitmapContextCreateImage(bmContext);
CGContextRelease(bmContext);
}
else {
CGImageRelease(partialImageRef);
partialImageRef = nil;
}
}
#endif
if (partialImageRef) {
UIImage *image = [UIImage imageWithCGImage:partialImageRef scale:1 orientation:orientation];
NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL];
UIImage *scaledImage = [self scaledImageForKey:key image:image];
if (self.shouldDecompressImages) {
image = [UIImage decodedImageWithImage:scaledImage];
}
else {
image = scaledImage;
}
CGImageRelease(partialImageRef);
dispatch_main_sync_safe(^{
if (self.completedBlock) {
self.completedBlock(image, nil, nil, NO);
}
});
}
}
CFRelease(imageSource);
}
if (self.progressBlock) {
self.progressBlock(self.imageData.length, self.expectedSize);
}
}
+ (UIImageOrientation)orientationFromPropertyValue:(NSInteger)value {
switch (value) {
case 1:
return UIImageOrientationUp;
case 3:
return UIImageOrientationDown;
case 8:
return UIImageOrientationLeft;
case 6:
return UIImageOrientationRight;
case 2:
return UIImageOrientationUpMirrored;
case 4:
return UIImageOrientationDownMirrored;
case 5:
return UIImageOrientationLeftMirrored;
case 7:
return UIImageOrientationRightMirrored;
default:
return UIImageOrientationUp;
}
}
- (UIImage *)scaledImageForKey:(NSString *)key image:(UIImage *)image {
return SDScaledImageForKey(key, image);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection {
SDWebImageDownloaderCompletedBlock completionBlock = self.completedBlock;
#synchronized(self) {
CFRunLoopStop(CFRunLoopGetCurrent());
self.thread = nil;
self.connection = nil;
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:self];
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadFinishNotification object:self];
});
}
if (![[NSURLCache sharedURLCache] cachedResponseForRequest:_request]) {
responseFromCached = NO;
}
if (completionBlock) {
if (self.options & SDWebImageDownloaderIgnoreCachedResponse && responseFromCached) {
completionBlock(nil, nil, nil, YES);
} else if (self.imageData) {
UIImage *image = [UIImage sd_imageWithData:self.imageData];
NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL];
image = [self scaledImageForKey:key image:image];
// Do not force decoding animated GIFs
if (!image.images) {
if (self.shouldDecompressImages) {
image = [UIImage decodedImageWithImage:image];
}
}
if (CGSizeEqualToSize(image.size, CGSizeZero)) {
completionBlock(nil, nil, [NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:#{NSLocalizedDescriptionKey : #"Downloaded image has 0 pixels"}], YES);
}
else {
completionBlock(image, self.imageData, nil, YES);
}
} else {
completionBlock(nil, nil, [NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:#{NSLocalizedDescriptionKey : #"Image data is nil"}], YES);
}
}
self.completionBlock = nil;
[self done];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
#synchronized(self) {
CFRunLoopStop(CFRunLoopGetCurrent());
self.thread = nil;
self.connection = nil;
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:self];
});
}
if (self.completedBlock) {
self.completedBlock(nil, nil, error, YES);
}
self.completionBlock = nil;
[self done];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
responseFromCached = NO; // If this method is called, it means the response wasn't read from cache
if (self.request.cachePolicy == NSURLRequestReloadIgnoringLocalCacheData) {
// Prevents caching of responses
return nil;
}
else {
return cachedResponse;
}
}
- (BOOL)shouldContinueWhenAppEntersBackground {
return self.options & SDWebImageDownloaderContinueInBackground;
}
- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection __unused *)connection {
return self.shouldUseCredentialStorage;
}
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
if (!(self.options & SDWebImageDownloaderAllowInvalidSSLCertificates) &&
[challenge.sender respondsToSelector:#selector(performDefaultHandlingForAuthenticationChallenge:)]) {
[challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge];
} else {
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
}
} else {
if ([challenge previousFailureCount] == 0) {
if (self.credential) {
[[challenge sender] useCredential:self.credential forAuthenticationChallenge:challenge];
} else {
[[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];
}
} else {
[[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];
}
}
}
#end
The line with the error is,
CFRunLoopRun();

Browse All Albums using MWPhotoBrowser

I can't forever read and try to understand the whole codes of MWPhotoBrowser's Example Project. I can't figure out where does this project get the Photos data. I've been trying to understand the project since last week.
So here's the thing, I'm trying to make an app that uses this MWPhotoBrowser (https://github.com/mwaterfall/MWPhotoBrowser/blob/master/README.md) open source project/library. An app that can browse all the albums in my phone but using the MWPhotoBrowser.
In the example proejct of the MWPhotoBrowser, there's a sample code how to browse the local photos of the phone. There are lots of examples but I managed to delete some of them and retain just the last one option. - Library Photos and Videos (Case:9 if you're going to look at the code).
What I have done so far:
Implement the open source project (Gallery Viewer App) from developer.apple.com - successfully implemented, but I'm not satisfied because MWPhotoBrowser is better and cooler.
Edit the Sample Project of MWPhotoBrowser.
CODE:
//
// Menu.m
// MWPhotoBrowser
//
// Created by Michael Waterfall on 21/10/2010.
// Copyright 2010 d3i. All rights reserved.
//
#import <Photos/Photos.h>
#import "Menu.h"
#import "SDImageCache.h"
#import "MWCommon.h"
#implementation Menu
#pragma mark -
#pragma mark View
- (void)viewDidLoad {
[super viewDidLoad];
// Test toolbar hiding
// [self setToolbarItems: #[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:nil action:nil]]];
// [[self navigationController] setToolbarHidden:NO animated:NO];
NSLog(#"view did load....");
self.title = #"MWPhotoBrowser";
// Clear cache for testing
[[SDImageCache sharedImageCache] clearDisk];
[[SDImageCache sharedImageCache] clearMemory];
[self loadAssets];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// self.navigationController.navigationBar.barTintColor = [UIColor greenColor];
// self.navigationController.navigationBar.translucent = NO;
// [self.navigationController setNavigationBarHidden:YES animated:YES];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
// [self.navigationController setNavigationBarHidden:NO animated:YES];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
- (BOOL)prefersStatusBarHidden {
return NO;
}
- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation {
return UIStatusBarAnimationNone;
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSInteger rows = 1;
#synchronized(_assets) {
if (_assets.count) rows++;
}
return rows;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Create
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
cell.accessoryType = _segmentedControl.selectedSegmentIndex == 0 ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone;
// Configure
switch (indexPath.row) {
case 0: {
cell.textLabel.text = #"Library photos and videos";
cell.detailTextLabel.text = #"media from device library";
break;
}
default: break;
}
return cell;
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Did Select...");
// Browser
NSMutableArray *photos = [[NSMutableArray alloc] init];
NSMutableArray *thumbs = [[NSMutableArray alloc] init];
MWPhoto *photo, *thumb;
BOOL displayActionButton = YES;
BOOL displaySelectionButtons = NO;
BOOL displayNavArrows = NO;
BOOL enableGrid = YES;
BOOL startOnGrid = NO;
BOOL autoPlayOnAppear = NO;
//#synchronized(_assets) {
NSMutableArray *copy = [_assets copy];
if (NSClassFromString(#"PHAsset")) {
// Photos library
UIScreen *screen = [UIScreen mainScreen];
CGFloat scale = screen.scale;
// Sizing is very rough... more thought required in a real implementation
CGFloat imageSize = MAX(screen.bounds.size.width, screen.bounds.size.height) * 1.5;
CGSize imageTargetSize = CGSizeMake(imageSize * scale, imageSize * scale);
CGSize thumbTargetSize = CGSizeMake(imageSize / 3.0 * scale, imageSize / 3.0 * scale);
for (PHAsset *asset in copy) {
[photos addObject:[MWPhoto photoWithAsset:asset targetSize:imageTargetSize]];
[thumbs addObject:[MWPhoto photoWithAsset:asset targetSize:thumbTargetSize]];
}
}
else {
// Assets library
for (ALAsset *asset in copy) {
MWPhoto *photo = [MWPhoto photoWithURL:asset.defaultRepresentation.url];
[photos addObject:photo];
MWPhoto *thumb = [MWPhoto photoWithImage:[UIImage imageWithCGImage:asset.thumbnail]];
[thumbs addObject:thumb];
if ([asset valueForProperty:ALAssetPropertyType] == ALAssetTypeVideo) {
photo.videoURL = asset.defaultRepresentation.url;
thumb.isVideo = true;
}
}
}
//}
self.photos = photos;
self.thumbs = thumbs;
// Create browser
MWPhotoBrowser *browser = [[MWPhotoBrowser alloc] initWithDelegate:self];
browser.displayActionButton = displayActionButton;
browser.displayNavArrows = displayNavArrows;
browser.displaySelectionButtons = displaySelectionButtons;
browser.alwaysShowControls = displaySelectionButtons;
browser.zoomPhotosToFill = YES;
browser.enableGrid = enableGrid;
browser.startOnGrid = startOnGrid;
browser.enableSwipeToDismiss = NO;
browser.autoPlayOnAppear = autoPlayOnAppear;
[browser setCurrentPhotoIndex:0];
// Test custom selection images
// browser.customImageSelectedIconName = #"ImageSelected.png";
// browser.customImageSelectedSmallIconName = #"ImageSelectedSmall.png";
// Reset selections
if (displaySelectionButtons) {
_selections = [NSMutableArray new];
for (int i = 0; i < photos.count; i++) {
[_selections addObject:[NSNumber numberWithBool:NO]];
}
}
// Show
[self.navigationController pushViewController:browser animated:YES];
}
#pragma mark - MWPhotoBrowserDelegate
- (NSUInteger)numberOfPhotosInPhotoBrowser:(MWPhotoBrowser *)photoBrowser {
return _photos.count;
}
- (id <MWPhoto>)photoBrowser:(MWPhotoBrowser *)photoBrowser photoAtIndex:(NSUInteger)index {
if (index < _photos.count)
return [_photos objectAtIndex:index];
return nil;
}
- (id <MWPhoto>)photoBrowser:(MWPhotoBrowser *)photoBrowser thumbPhotoAtIndex:(NSUInteger)index {
if (index < _thumbs.count)
return [_thumbs objectAtIndex:index];
return nil;
}
//- (MWCaptionView *)photoBrowser:(MWPhotoBrowser *)photoBrowser captionViewForPhotoAtIndex:(NSUInteger)index {
// MWPhoto *photo = [self.photos objectAtIndex:index];
// MWCaptionView *captionView = [[MWCaptionView alloc] initWithPhoto:photo];
// return [captionView autorelease];
//}
- (void)photoBrowser:(MWPhotoBrowser *)photoBrowser actionButtonPressedForPhotoAtIndex:(NSUInteger)index {
NSLog(#"ACTION!");
}
- (void)photoBrowser:(MWPhotoBrowser *)photoBrowser didDisplayPhotoAtIndex:(NSUInteger)index {
NSLog(#"Did start viewing photo at index %lu", (unsigned long)index);
}
- (BOOL)photoBrowser:(MWPhotoBrowser *)photoBrowser isPhotoSelectedAtIndex:(NSUInteger)index {
return [[_selections objectAtIndex:index] boolValue];
}
//- (NSString *)photoBrowser:(MWPhotoBrowser *)photoBrowser titleForPhotoAtIndex:(NSUInteger)index {
// return [NSString stringWithFormat:#"Photo %lu", (unsigned long)index+1];
//}
- (void)photoBrowser:(MWPhotoBrowser *)photoBrowser photoAtIndex:(NSUInteger)index selectedChanged:(BOOL)selected {
[_selections replaceObjectAtIndex:index withObject:[NSNumber numberWithBool:selected]];
NSLog(#"Photo at index %lu selected %#", (unsigned long)index, selected ? #"YES" : #"NO");
}
//////////////
#pragma mark - Load Assets
- (void)loadAssets {
if (NSClassFromString(#"PHAsset")) {
// Check library permissions
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
if (status == PHAuthorizationStatusNotDetermined) {
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
if (status == PHAuthorizationStatusAuthorized) {
[self performLoadAssets];
}
}];
} else if (status == PHAuthorizationStatusAuthorized) {
[self performLoadAssets];
}
} else {
// Assets library
[self performLoadAssets];
}
}
- (void)performLoadAssets {
// Initialise
_assets = [NSMutableArray new];
// Load
if (NSClassFromString(#"PHAsset")) {
// Photos library iOS >= 8
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
PHFetchOptions *options = [PHFetchOptions new];
options.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"creationDate" ascending:NO]];
PHFetchResult *fetchResults = [PHAsset fetchAssetsWithOptions:options];
[fetchResults enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[_assets addObject:obj];
}];
if (fetchResults.count > 0) {
// [self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
}
});
} else {
// Assets Library iOS < 8
_ALAssetsLibrary = [[ALAssetsLibrary alloc] init];
// Run in the background as it takes a while to get all assets from the library
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSMutableArray *assetGroups = [[NSMutableArray alloc] init];
NSMutableArray *assetURLDictionaries = [[NSMutableArray alloc] init];
// Process assets
void (^assetEnumerator)(ALAsset *, NSUInteger, BOOL *) = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (result != nil) {
NSString *assetType = [result valueForProperty:ALAssetPropertyType];
if ([assetType isEqualToString:ALAssetTypePhoto] || [assetType isEqualToString:ALAssetTypeVideo]) {
[assetURLDictionaries addObject:[result valueForProperty:ALAssetPropertyURLs]];
NSURL *url = result.defaultRepresentation.url;
[_ALAssetsLibrary assetForURL:url
resultBlock:^(ALAsset *asset) {
if (asset) {
#synchronized(_assets) {
[_assets addObject:asset];
if (_assets.count == 1) {
// Added first asset so reload data
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
}
}
}
}
failureBlock:^(NSError *error){
NSLog(#"operation was not successfull!");
}];
}
}
};
// Process groups
void (^ assetGroupEnumerator) (ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop) {
if (group != nil) {
[group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:assetEnumerator];
[assetGroups addObject:group];
}
};
// Process!
[_ALAssetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:assetGroupEnumerator
failureBlock:^(NSError *error) {
NSLog(#"There is an error");
}];
});
}
}
#end
Next, I tried to make a ViewController inside the Storyboard of the sample project, disconnected the connection between the navigation controller and the Table View controller. I Connected the Navigation Controller to ViewController. I then assigned my newly made class named: MainViewController.m to ViewController in the storyboard.
I copied all the codes, or rather, copy all the implementation of codes in the Main.m (the class connected to Table View of the sample project), to my MainViewController.m. So here's the code of mine so far:
//
// MainViewController.m
// MWPhotoBrowser
//
// Created by Glenn on 9/28/15.
// Copyright (
c) 2015 Michael Waterfall. All rights reserved.
//
#import "MainViewController.h"
#import <Photos/Photos.h>
// #import "Menu.h"
#import "SDImageCache.h"
#import "MWCommon.h"
#interface MainViewController ()
{
MWPhotoBrowser *browser;
}
#end
#implementation MainViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self mwSetup];
self.title = #"MWPhotoBrowser";
// Clear cache for testing
[[SDImageCache sharedImageCache] clearDisk];
[[SDImageCache sharedImageCache] clearMemory];
[self loadAssets];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// self.navigationController.navigationBar.barTintColor = [UIColor greenColor];
// self.navigationController.navigationBar.translucent = NO;
// [self.navigationController setNavigationBarHidden:YES animated:YES];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
// [self.navigationController setNavigationBarHidden:NO animated:YES];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
- (BOOL)prefersStatusBarHidden {
return NO;
}
- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation {
return UIStatusBarAnimationNone;
}
- (void)mwSetup
{
NSLog(#"Did Select...");
// Browser
NSMutableArray *photos = [[NSMutableArray alloc] init];
NSMutableArray *thumbs = [[NSMutableArray alloc] init];
MWPhoto *photo, *thumb;
BOOL displayActionButton = YES;
BOOL displaySelectionButtons = NO;
BOOL displayNavArrows = NO;
BOOL enableGrid = YES;
BOOL startOnGrid = NO;
BOOL autoPlayOnAppear = NO;
//#synchronized(_assets) {
NSMutableArray *copy = [_assets copy];
if (NSClassFromString(#"PHAsset")) {
// Photos library
UIScreen *screen = [UIScreen mainScreen];
CGFloat scale = screen.scale;
// Sizing is very rough... more thought required in a real implementation
CGFloat imageSize = MAX(screen.bounds.size.width, screen.bounds.size.height) * 1.5;
CGSize imageTargetSize = CGSizeMake(imageSize * scale, imageSize * scale);
CGSize thumbTargetSize = CGSizeMake(imageSize / 3.0 * scale, imageSize / 3.0 * scale);
for (PHAsset *asset in copy) {
[photos addObject:[MWPhoto photoWithAsset:asset targetSize:imageTargetSize]];
[thumbs addObject:[MWPhoto photoWithAsset:asset targetSize:thumbTargetSize]];
}
}
else {
// Assets library
for (ALAsset *asset in copy) {
MWPhoto *photo = [MWPhoto photoWithURL:asset.defaultRepresentation.url];
[photos addObject:photo];
MWPhoto *thumb = [MWPhoto photoWithImage:[UIImage imageWithCGImage:asset.thumbnail]];
[thumbs addObject:thumb];
if ([asset valueForProperty:ALAssetPropertyType] == ALAssetTypeVideo) {
photo.videoURL = asset.defaultRepresentation.url;
thumb.isVideo = true;
}
}
}
//}
self.photos = photos;
self.thumbs = thumbs;
// Create browser
browser = [[MWPhotoBrowser alloc] initWithDelegate:self];
browser.displayActionButton = displayActionButton;
browser.displayNavArrows = displayNavArrows;
browser.displaySelectionButtons = displaySelectionButtons;
browser.alwaysShowControls = displaySelectionButtons;
browser.zoomPhotosToFill = YES;
browser.enableGrid = enableGrid;
browser.startOnGrid = startOnGrid;
browser.enableSwipeToDismiss = NO;
browser.autoPlayOnAppear = autoPlayOnAppear;
[browser setCurrentPhotoIndex:0];
// Test custom selection images
// browser.customImageSelectedIconName = #"ImageSelected.png";
// browser.customImageSelectedSmallIconName = #"ImageSelectedSmall.png";
// Reset selections
if (displaySelectionButtons) {
_selections = [NSMutableArray new];
for (int i = 0; i < photos.count; i++) {
[_selections addObject:[NSNumber numberWithBool:NO]];
}
}
// Show
[self.navigationController pushViewController:browser animated:YES];
//[self.view addSubview:browser.view];
}
#pragma mark - MWPhotoBrowserDelegate
- (NSUInteger)numberOfPhotosInPhotoBrowser:(MWPhotoBrowser *)photoBrowser {
return _photos.count;
}
- (id <MWPhoto>)photoBrowser:(MWPhotoBrowser *)photoBrowser photoAtIndex:(NSUInteger)index {
if (index < _photos.count)
return [_photos objectAtIndex:index];
return nil;
}
- (id <MWPhoto>)photoBrowser:(MWPhotoBrowser *)photoBrowser thumbPhotoAtIndex:(NSUInteger)index {
if (index < _thumbs.count)
return [_thumbs objectAtIndex:index];
return nil;
}
//- (MWCaptionView *)photoBrowser:(MWPhotoBrowser *)photoBrowser captionViewForPhotoAtIndex:(NSUInteger)index {
// MWPhoto *photo = [self.photos objectAtIndex:index];
// MWCaptionView *captionView = [[MWCaptionView alloc] initWithPhoto:photo];
// return [captionView autorelease];
//}
- (void)photoBrowser:(MWPhotoBrowser *)photoBrowser actionButtonPressedForPhotoAtIndex:(NSUInteger)index {
NSLog(#"ACTION!");
}
- (void)photoBrowser:(MWPhotoBrowser *)photoBrowser didDisplayPhotoAtIndex:(NSUInteger)index {
NSLog(#"Did start viewing photo at index %lu", (unsigned long)index);
}
- (BOOL)photoBrowser:(MWPhotoBrowser *)photoBrowser isPhotoSelectedAtIndex:(NSUInteger)index {
return [[_selections objectAtIndex:index] boolValue];
}
//- (NSString *)photoBrowser:(MWPhotoBrowser *)photoBrowser titleForPhotoAtIndex:(NSUInteger)index {
// return [NSString stringWithFormat:#"Photo %lu", (unsigned long)index+1];
//}
- (void)photoBrowser:(MWPhotoBrowser *)photoBrowser photoAtIndex:(NSUInteger)index selectedChanged:(BOOL)selected {
[_selections replaceObjectAtIndex:index withObject:[NSNumber numberWithBool:selected]];
NSLog(#"Photo at index %lu selected %#", (unsigned long)index, selected ? #"YES" : #"NO");
}
#pragma mark - Load Assets
- (void)loadAssets {
if (NSClassFromString(#"PHAsset")) {
// Check library permissions
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
if (status == PHAuthorizationStatusNotDetermined) {
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
if (status == PHAuthorizationStatusAuthorized) {
[self performLoadAssets];
}
}];
} else if (status == PHAuthorizationStatusAuthorized) {
[self performLoadAssets];
}
} else {
// Assets library
[self performLoadAssets];
}
}
- (void)performLoadAssets {
// Initialise
_assets = [NSMutableArray new];
// Load
if (NSClassFromString(#"PHAsset")) {
// Photos library iOS >= 8
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
PHFetchOptions *options = [PHFetchOptions new];
options.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"creationDate" ascending:NO]];
PHFetchResult *fetchResults = [PHAsset fetchAssetsWithOptions:options];
[fetchResults enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[_assets addObject:obj];
}];
if (fetchResults.count > 0) {
[browser reloadData]; }
});
} else {
// Assets Library iOS < 8
_ALAssetsLibrary = [[ALAssetsLibrary alloc] init];
// Run in the background as it takes a while to get all assets from the library
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSMutableArray *assetGroups = [[NSMutableArray alloc] init];
NSMutableArray *assetURLDictionaries = [[NSMutableArray alloc] init];
// Process assets
void (^assetEnumerator)(ALAsset *, NSUInteger, BOOL *) = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (result != nil) {
NSString *assetType = [result valueForProperty:ALAssetPropertyType];
if ([assetType isEqualToString:ALAssetTypePhoto] || [assetType isEqualToString:ALAssetTypeVideo]) {
[assetURLDictionaries addObject:[result valueForProperty:ALAssetPropertyURLs]];
NSURL *url = result.defaultRepresentation.url;
[_ALAssetsLibrary assetForURL:url
resultBlock:^(ALAsset *asset) {
if (asset) {
#synchronized(_assets) {
[_assets addObject:asset];
if (_assets.count == 1) {
// Added first asset so reload data
[browser reloadData];
}
}
}
}
failureBlock:^(NSError *error){
NSLog(#"operation was not successfull!");
}];
}
}
};
// Process groups
void (^ assetGroupEnumerator) (ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop) {
if (group != nil) {
[group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:assetEnumerator];
[assetGroups addObject:group];
}
};
// Process!
[_ALAssetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:assetGroupEnumerator
failureBlock:^(NSError *error) {
NSLog(#"There is an error");
}];
});
}
}
#end
Please help. And can someone help me edit the format of my 2nd code? Thanks.
Okay, so I got it working. Basically, the MWPhotoBrowser needs a first view controller before loading itself.
For instance, in the sample project, the first screen is the Table View. Then you will select between the 9 rows, after that, the MWPhotoBrowser viewcontroller will be showed.
In my implementation, I just made a first view controller, and then added a button. When you click the button, the MWPhotoBrowser will be showed.
So that's how MWPhotoBrowser works. It doesn't load the photos and videos if you push the MWPhotoBrowser inside the ViewWillAppear, ViewDidLoad, ViewDidAppear.
Now, I have to learn or know how to load videos and photos from different album.

IOS dev: Just need help in exc_bad_access error

Help, my app is showing thread 1 error exc_bad_access(code=1, address=0x2000001) on the last curly brace of my PlayViewController.
Note: this happen when I click the continue button on my GuessViewController. The continue button calls the the PlayViewController.
What i already did:
enabled ZOMBIE
close db
my GuessViewController:
#import "GuessViewController.h"
#import "PlayViewController.h"
#import "ViewController.h"
#interface GuessViewController ()
#end
#implementation GuessViewController
#synthesize userInput = _userInput;
#synthesize gword;
#synthesize gletter;
int score = 0;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
_userInput.delegate = self;
self.scoreLabel.text = [NSString stringWithFormat:#"%d", score];
// Do any additional setup after loading the view.
}
-(void)touchesBegan:(NSSet*)touches withEvent: (UIEvent *) event{
[_userInput resignFirstResponder];
}
-(BOOL)textFieldShouldReturn: (UITextField*)textField {
if(textField){
[textField resignFirstResponder];
}
return NO;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)checkAnswer:(id)sender {
NSLog(#"%#", gword);
NSLog(#"%#", gletter);
NSString *temp = self.userInput.text;
unichar temp2 = [temp characterAtIndex: 0];
NSString *userletter= [NSString stringWithFormat:#"%C", temp2];
NSString *message1 = #"The word is ";
NSString *message2= [NSString stringWithFormat:#"%#", gword];
NSString *fm = [message1 stringByAppendingString:message2];
if([userletter isEqualToString:gletter]){
UIAlertView *checkAlert = [[UIAlertView alloc] initWithTitle:#"Got it Right" message:fm delegate:self cancelButtonTitle:#"Continue" otherButtonTitles:#"Back to Main Menu", nil];
score++;
self.scoreLabel.text = [NSString stringWithFormat:#"%d", score];
[checkAlert show];
}else{
UIAlertView *checkAlert = [[UIAlertView alloc] initWithTitle:#"Wrong" message:fm delegate:self cancelButtonTitle:#"Continue" otherButtonTitles:#"Back to Main Menu", nil];
[checkAlert show];
}
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if(buttonIndex ==0){
PlayViewController *playViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Play"];
[self presentViewController:playViewController animated:YES completion: Nil];
} else {
ViewController *viewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Main"];
[self presentViewController:viewController animated:YES completion: Nil];
}
}
#end
My PlayViewController:
#import "PlayViewController.h"
#import "GuessViewController.h"
#import <sqlite3.h>
#import "Word.h"
#interface PlayViewController ()
#end
#implementation PlayViewController
#synthesize thewords;
NSString *word;
NSTimer *myTimer;
int randomIndex;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[self wordList];
[super viewDidLoad];
// Do any additional setup after loading the view.
self.listChar.text = #" ";
int r = (arc4random()%[self.thewords count]);
word = [self.thewords objectAtIndex:r];
NSLog(#"%#", word);
randomIndex = (arc4random()%word.length);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
- (IBAction)startGame:(id)sender {
myTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(listLetter:) userInfo:nil repeats:YES];
}
- (void)listLetter:(NSTimer *)timer
{
static int i = 0;
unichar letter;
if(randomIndex == i){
letter = ' ';
} else {
letter = [word characterAtIndex: i];
}
self.listChar.text = [NSString stringWithFormat:#"%C", letter];
if (++i == word.length) {
[timer invalidate];
i = 0;
GuessViewController *guessViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Guess"];
//passing some data
guessViewController.word = word;
guessViewController.letter = [NSString stringWithFormat:#"%C", [word characterAtIndex: randomIndex]];
[self presentViewController:guessViewController animated:YES completion: Nil];
}
}
-(NSMutableArray *) wordList {
thewords = [[NSMutableArray alloc] initWithCapacity:26];
#try {
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"LetterHunter.sqlite"];
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if(!success){
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
if(!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK)){
NSLog(#"An error has occured");
}
const char *sql = "SELECT * FROM WordList";
sqlite3_stmt*sqlStatement;
if(sqlite3_prepare_v2(db, sql, -1, &sqlStatement, NULL)!=SQLITE_OK){
NSLog(#"Problem with prepare statement1");
} else {
while(sqlite3_step(sqlStatement) == SQLITE_ROW){
Word *word = [[Word alloc]init];
word.wordfromdb = [NSString stringWithUTF8String:(char*)sqlite3_column_text(sqlStatement, 1)];
[thewords addObject: word.wordfromdb];
}
}
sqlite3_finalize(sqlStatement);
}
#catch (NSException *exception) {
NSLog(#"Problem with prepare statement2");
}
#finally {
sqlite3_close(db);
}
}
#end
As suggested below, I tried doing this instead but still there's the error
while(sqlite3_step(sqlStatement) == SQLITE_ROW){
NSString *temp = #"";
temp = [NSString stringWithUTF8String:(char*)sqlite3_column_text(sqlStatement, 1)];
[thewords addObject: temp;
}
From debug stack, it's a problem about autorelease. And I think the problem maybe in
if(!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK)){
I can't find db define. So I think it should be a instance property.
Try this:
DbClass *tempDb = nil;
if(!(sqlite3_open([dbPath UTF8String], &tempDb) == SQLITE_OK)){
self.db = tempDb;
What is wordfromdb? If it is string variable or any other datatype then add directly that into an array...
I think there is not need to create word object here as anyway your are not storing word object in array.
It looks to me an issue with word object. You are crating word object but adding its property only and not entire object.

Resources