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
CodePudding user response:
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: