Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
In Objective-C it is quite common to use boolean pointers to stop an enumeration e.g.:
[myArray rh_iterate:^(id element, int index, BOOL *stop){
// Do cool stuff
*stop = YES;
}];
I've implemented this like:
// This is in a category of NSArray
- (void)rh_iterate:(void (^)(id, int, BOOL *))block
{
if (!block) { return; }
BOOL stop = NO;
for (int i = 0; i < self.count; i++) {
block(self[i], i, &stop);
if (stop) { return; }
}
}
I'm now implementing my version of this in Swift but am not relying on any Objective-C source code. I know that swift likes to restrict the access of pointers so what's the best way to go about implementing this? (Ideally completely avoiding pointers.)
EDIT:
The most direct way is:
func rh_iterate(callback: (Element, Int, UnsafeMutablePointer<Bool>) -> ()) {
var stop: Bool = false
for (index, element) in self.enumerate() {
callback(element, index, &stop)
if stop { return }
}
}
Since AMomchilov deleted his answer, I'll put it back.
The direct equivalent to the BOOL* pattern would be an inout variable
extension Array
{
func iterateWithStop(closure: (Element, inout shouldStop: Bool) -> ()) -> Bool
{
var shouldStop = false
for e in self
{
guard !shouldStop else { return false }
closure(e, shouldStop: &shouldStop)
}
return !shouldStop
}
}
The function returns true if the iteration completed without the closure trying to stop it, false if the closure did try to stop it.
You would use it like this:
let myArray = [1, 2, 3, -1, 4]
var sum = 0
let didProcessAllElements = myArray.iterateWithStop{ e, shouldStop in
if e < 0
{
shouldStop = true
}
else
{
sum += e
}
}
// sum == 6
(tested in a playground on Swift 2.2)
Related
I've been having issues converting an Objective-C snippet to Swift that uses NSData and CoreBluetooth. I have looked at this question and a couple others dealing with NSData in Swift but haven't had any success.
Objective-C Snippet:
- (CGFloat) minTemperature
{
CGFloat result = NAN;
int16_t value = 0;
// characteristic is a CBCharacteristic
if (characteristic) {
[[characteristic value] getBytes:&value length:sizeof (value)];
result = (CGFloat)value / 10.0f;
}
return result;
}
What I have so far in Swift (not working):
func minTemperature() -> CGFloat {
let bytes = [UInt8](characteristic?.value)
let pointer = UnsafePointer<UInt8>(bytes)
let fPointer = pointer.withMemoryRebound(to: Int16.self, capacity: 2) { return $0 }
value = Int16(fPointer.pointee)
result = CGFloat(value / 10) // not correct value
return result
}
Does the logic look wrong here? Thanks!
One error is in
let fPointer = pointer.withMemoryRebound(to: Int16.self, capacity: 2) { return $0 }
because the rebound pointer $0 is only valid inside the closure and must
not be passed to the outside. Also the capacity should be 1 for a
single Int16 value. Another problem is the integer division in
result = CGFloat(value / 10)
which truncates the result (as already observed by the4kman).
Creating an [UInt8] array from the data is not necessary, the
withUnsafeBytes() method of Data can be used instead.
Finally you could return nil (instead of "not a number") if no
characteristic value is given:
func minTemperature() -> CGFloat? {
guard let value = characteristic?.value else {
return nil
}
let i16val = value.withUnsafeBytes { (ptr: UnsafePointer<Int16>) in
ptr.pointee
}
return CGFloat(i16val) / 10.0
}
You should make the return value optional and check if characteristic is nil in the beginning with a guard. You should also explicitly convert the value to CGFloat, then divide it by 10.
func minTemperature() -> CGFloat? {
guard characteristic != nil else {
return nil
}
let bytes = [UInt8](characteristic!.value)
let pointer = UnsafePointer<UInt8>(bytes)
let fPointer = pointer.withMemoryRebound(to: Int16.self, capacity: 2) { return $0 }
let value = Int16(fPointer.pointee)
result = CGFloat(value) / 10
return result
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have a chat controller with a WKInterfaceTable of canned messages and each table row is a different kind of rowController that comes with a WKInterfaceTable in WatchKit.
Each rowController references a MessageSource and MessageType which is defined in an enum.
The declaration of my enum looks good but the implementation syntax of the related dictionary needs some help.
Another issue related to the same blocks is the Swift conversion of my properties. I'm not sure if I have declared them correctly therefore they may be affecting the same blocks.
I have tried to trim as much code as possible because I know SO likes it that way. There are a few references in different functions though so I included what was needed to keep things explicit.
Obj-C
controller.m
typedef enum {
MessageSourceIncoming = 1,
MessageSourceOutgoing = 2
} MessageSource;
typedef enum {
MessageTypeText = 1,
MessageTypeVoice = 2,
MessageTypeImage = 3
} MessageType;
- (void)setupTable {
_messages = [NSMutableArray array];
for (int i = 0; i < rand()%20; i++) {
[_messages addObject:#{#"msg":#[#"Hi", #"OK", #"Nice to meet you", #"Fine"][rand()%4], #"source":#(rand()%2), #"type":#(rand()%3)}];
}
// clear the table rows
[_table removeRowsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, _table.numberOfRows)]];
for (int i = 0; i < _messages.count; i++) {
NSDictionary *messageDic = _messages[i];
[self insertRowForMessage:messageDic];
}
}
- (void)willActivate {
[_table scrollToRowAtIndex:_table.numberOfRows - 1];
if (_shouldSendVoice) {
NSDictionary *messageDic = #{#"source":#(MessageSourceOutgoing), #"type":#(MessageTypeVoice), #"path":_shouldSendVoice};
[_messages addObject:messageDic];
[self insertRowForMessage:messageDic];
_shouldSendVoice = nil;
}
}
Let's break it down:
enum MessageSource: Int {
case MessageSourceIncoming = 1
case MessageSourceOutgoing = 2
}
enum MessageType: Int {
case MessageTypeText = 1
case MessageTypeVoice = 2
case MessageTypeImage = 3
}
Nothing wrong with enums, however it's a question whether you need to give them integer values. You don't have to assign every value though:
enum MessageType: Int {
case MessageTypeText = 1
case MessageTypeVoice
case MessageTypeImage
}
would work just fine and the values would be the same.
var chat = NSDictionary()
var messages = NSMutableArray()
var shouldSendVoice = NSString()
chat should probably be a Swift dictionary but we don't have enough information to set the type so I will skip it.
shouldSendVoice looks like a boolean, why should we assign a NSString to it? I am not sure how you are using that one, so I won't rename it but let's make an optional string from it.
messages should be a Swift array. Let's create a type for Message:
struct Message {
let message: String?
let source: MessageSource
let type: MessageType
let path: String?
}
var chat = NSDictionary() // let's ignore this
var messages: [Message] = [] // empty swift array of messages
var shouldSendVoice: String? = nil // optional String
Now, let's just rewrite the rest:
override func willActivate() {
super.willActivate()
self.table.scrollToRowAtIndex(table.numberOfRows - 1)
// in Obj-C this was checking for nil!, we have to check explicitly in Swift
if let shouldSendVoice = self.shouldSendVoice {
// let's not use Dictionaries for custom objects
let message = Message(message: nil, source: .MessageSourceIncoming, type: .MessageTypeVoice, path: shouldSendVoice)
self.messages.append(message)
self.insertRowForMessage(message)
// I think you don't want new String here, just `nil`
shouldSendVoice = nil
}
}
func setupTable() {
// let's use a saner way to generate randoms
let numMessages = Int(arc4random_uniform(20))
self.messages = (0..<numMessages).map { _ in
let message = // randomize the message
let source = // randomize source
let type = // randomize type
return Message(message: message, source: source, type: type, path: nil)
}
// let's split multiple operations into separate lines to make code more readable
let indicesToRemove = NSIndexSet(indexesInRange:NSMakeRange(0, table.numberOfRows))
self.table.removeRowsAtIndexes(indicesToRemove)
// let's use for-in without using an index
for message in messages {
self.insertRowForMessage(message)
}
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
ive refined it a bit. Can someone change it to the correct way for me?
i also introduced a new variable isPrime i guess this is a bit better
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool {
int p = 7;
int d, isPrime = 0;
if (p % 2 != 0)
{
for (d = 2; d < p; d++) {
p % d;
}
if (p % d == 0)
{
isPrime = 1; //not prime
}
if (p % d != 0)
{
isPrime = 2; //is prime
}
if (isPrime == 1)
{
NSLog(#"its not prime");
}
if (isPrime == 2) {
NSLog(#"its prime");
}
}
else
NSLog(#"sorry");
}
return 0;
}
There's the well-known Sieve of Eratosthenes, but if you are writing a program that is just going to take one number as input and decide whether it's prime, the Sieve does more than you need (it finds all primes less than some value of your choice) so it may not be your most efficient choice of algorithm.
A couple other things about finding primes:
If you find that p is not even, you only have to try dividing it by odd numbers, that is, 3, 5, 7, 9, etc. (Yes, once you know it's not divisible by 3, technically you know it's not divisible by 9, but it may not be worthwhile or even efficient to account for such things in your algorithm.)
You don't have to try anything larger than sqrt(p) as a divisor. If you haven't found a divisor by then, you never will (except for 1 and p itself).
If you find a number that divides p, you can say immediately that p is not prime. (You might want to make sure you exit any loops then, too, otherwise you might end up printing the announcement that p is not prime more than once.)
... But you must never say that p is prime until the end of your algorithm, after all loops have completed. Until then, the most you can say is you haven't yet found a proof that p is not prime.
Above loop is fine , but you have to start from 3 rather than 2.
This is pseudo code for prime number calculation :
int num = 11;
NSString * res = null;
for(int i = 2 ;i<num ;i ++)
{
if(num%i == 0)
{
res = #"This is not a prime number";
break
}
else{
res = #"This is prime number";
}
}
try this
int p = 7;
int d, isPrime = 2;
if (p % 2 != 0)
{
for (d = 2; (d < p) && (isPrime == 2); d++) {
if (p % d == 0)
{
isPrime = 1; //not prime
}
if (p % d != 0)
{
isPrime = 2; //is prime
}
}
if (isPrime == 1)
{
NSLog(#"its not prime");
}
if (isPrime == 2) {
NSLog(#"its prime");
}
}
else
NSLog(#"sorry");
How do I stop a block enumeration?
myArray.enumerateObjectsUsingBlock( { object, index, stop in
//how do I stop the enumeration in here??
})
I know in obj-c you do this:
[myArray enumerateObjectsUsingBlock:^(id *myObject, NSUInteger idx, BOOL *stop) {
*stop = YES;
}];
In Swift 1:
stop.withUnsafePointer { p in p.memory = true }
In Swift 2:
stop.memory = true
In Swift 3 - 4:
stop.pointee = true
This has unfortunately changed every major version of Swift. Here's a breakdown:
Swift 1
stop.withUnsafePointer { p in p.memory = true }
Swift 2
stop.memory = true
Swift 3
stop.pointee = true
since XCode6 Beta4, the following way can be used instead:
let array: NSArray = // the array with some elements...
array.enumerateObjectsUsingBlock( { (object: AnyObject!, idx: Int, stop: UnsafePointer<ObjCBool>) -> Void in
// do something with the current element...
var shouldStop: ObjCBool = // true or false ...
stop.initialize(shouldStop)
})
The accepted answer is correct but will work for NSArrays only. Not for the Swift datatype Array. If you like you can recreate it with an extension.
extension Array{
func enumerateObjectsUsingBlock(enumerator:(obj:Any, idx:Int, inout stop:Bool)->Void){
for (i,v) in enumerate(self){
var stop:Bool = false
enumerator(obj: v, idx: i, stop: &stop)
if stop{
break
}
}
}
}
call it like
[1,2,3,4,5].enumerateObjectsUsingBlock({
obj, idx, stop in
let x = (obj as Int) * (obj as Int)
println("\(x)")
if obj as Int == 3{
stop = true
}
})
or for function with a block as the last parameter you can do
[1,2,3,4,5].enumerateObjectsUsingBlock(){
obj, idx, stop in
let x = (obj as Int) * (obj as Int)
println("\(x)")
if obj as Int == 3{
stop = true
}
}
Just stop = true
Since stop is declared as inout, swift will take care of mapping the indirection for you.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Well, I have been doing the project euler questions today, and I saw problem 3 and started programming in objective C in it and it appears, its not functioning correctly. Below is my code, pls check and let me what and which error I am making. I am currently using Xcode and the purpose of the script is to return a inputted numbers largest prime factor.
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool {
int number,primefactor, x;
bool isPrime;
NSLog (#"Please enter a number:");
scanf ("%i", &number);
for (primefactor = number;primefactor > 0;--primefactor)
{
if (number % primefactor == 0)
{
for (x = 2;x < primefactor;++x)
{
if (primefactor % x == 0)
{
isPrime = FALSE;
}
}
}
if (isPrime == TRUE)
{
NSLog (#"%i", primefactor);
break;
}
}
}
return 0;
}
I expected the program to return a value and yet, it didnt do so and exited with an exit code of 0. You may checkout the output at http://tinypic.com/r/24d28hv/8
The error in your code is that isPrime must be set to TRUE each time before
the primefactor candidate is checked:
for (primefactor = number;primefactor > 0;--primefactor)
{
if (number % primefactor == 0)
{
bool isPrime = TRUE; // <---- HERE
for (x = 2;x < primefactor;++x)
{
if (primefactor % x == 0)
{
isPrime = FALSE;
}
}
if (isPrime == TRUE)
{
NSLog (#"%i", primefactor);
break;
}
}
}
(Note that to solve http://projecteuler.net/problem=3 for the number 600851475143
you have to use a larger data type. That number does not fit into a 32-bit integer.
You might also have to find a more efficient algorithm.)