This my be the strangest error I've ever seen.
I'm creating a maze game that loads levels from text files, but if the file has more than three rows, it seems to randomly change most of my variables. I load in a text file then run through the lines and create an object at the proper location based on its letter.
Any advice?
Text File:
TTTTTTTTTTTTTTTTT
TTTTTTTTTTTTTTTTT
TTTTTTTTTTTTTTTTT
TTTTTRPPGPPDTTTTT
TTTTTPTPTPTPTTTTT
TTTTTPPPWPPPTTTTT
TTTTTPTPPPTPTTTTT
TTTTTPPPTPPPTTTTT
TTTTTPTPPPTPTTTTT
TTTTTUPPPPPLTTTTT
TTTTTTTTPTTTTTTTT
TTTTTTTTBTTTTTTTT
TTTTTTTTPTTTTTTTT
NSString *path = [[NSBundle mainBundle] pathForResource:#"map2c" ofType:#"txt"];
NSString *contents = [NSString stringWithContentsOfFile:path encoding:NSASCIIStringEncoding error:nil];
NSArray *lines = [contents componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"\r\n"]];
int y = 0;
for (NSString* line in lines) {
NSString* ty = #"TBGWUDLRP";
char *str = (char *)[line UTF8String];
char *str2 = (char*)[ty UTF8String];
grannyMoving = 2;
int x = str2[0];
char x2 = str2[1];
char GrannyStr = str2[2];
char wolfStr = str2[3];
char UpStr = str2[4];
char DownStr = str2[5];
char leftStr = str2[6];
char rightStr = str2[7];
char PathStr = str2[8];
y--;
maxY = y;
if (line.length) {
maxI = line.length;
for (int i = 0; i< line.length; i++) {
SKSpriteNode* tree = [SKSpriteNode spriteNodeWithImageNamed:#"tree3"];
tree.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(31, 31)];
tree.physicsBody.affectedByGravity = false;
tree.physicsBody.dynamic = NO;
tree.position = CGPointMake(64*i+20, 64*y+800);
tree.zPosition = -1* tree.position.y;
From the documentation:
This C string is a pointer to a structure inside the string object,
which may have a lifetime shorter than the string object and will
certainly not have a longer lifetime. Therefore, you should copy the C
string if it needs to be stored outside of the memory context in which
you use this property.
To fix this you have to make a copy of the characters returned by UTF8String. This answer provides two solutions.
Related
I'm playing around a bit with Core Image, CIFilter and RAW images. If I understand Apple's documentation correctly, to load a RAW image and display it in an image view, some code like this should do the trick:
NSURL *url = [NSURL URLWithString:#"file:///Users/emiel/Desktop/_MG_1087.CR2"];
// NSURL *url = [NSURL URLWithString:#"file:///Users/emiel/Desktop/_DSC0044.NEF"];
CIFilter *filter = [CIFilter filterWithImageURL:url options:nil];
NSLog(#"CIFilter: %#", filter);
CIImage *image = filter.outputImage;
NSCIImageRep *rep = [NSCIImageRep imageRepWithCIImage:image];
NSLog(#"%f - %f", rep.size.width, rep.size.height);
NSImage *nsImage = [[NSImage alloc] initWithSize:CGSizeMake(rep.size.width, rep.size.height)];
[nsImage addRepresentation:rep];
self.imageView.image = nsImage;
This code works fine for the .NEF (Nikon RAW) file, but the CR2 (Canon RAW) file gives me a totally black image. The image dimensions of the black image are correct though. What is going wrong here? Do I need to set some default to a non-default value? Preview/Aperture/iPhoto/etc all work fine with my .CR2 image, so it is possible to read them.
The only difference I can find is that apparently, for the CR2 file a version 6 of the decoder is used, and the NEF file is decoded by version 5. If I set the CR2 to be decoded by version 5 all works, but this seems to be a weird solution since I don't know if there is a version 5 or 6 or whatever for other RAW image formats.
NEF File:
{CIRAWFilterImpl {
inputBias = 3;
inputBoost = 1;
inputBoostShadowAmount = "0.9";
inputColorNoiseReductionAmount = "0.5";
inputDecoderVersion = 5;
inputDraftMode = 0;
inputEV = 0;
inputEnableNoiseTracking = 1;
inputEnableSharpening = 1;
inputEnableVendorLensCorrection = 0;
inputIgnoreOrientation = "<null>";
inputImageOrientation = 1;
inputLinearSpaceFilter = "<null>";
inputLuminanceNoiseReductionAmount = "0.1";
inputNeutralChromaticityX = "0.4212473792917087";
inputNeutralChromaticityY = "0.4060714400950335";
inputNeutralLocation = "[]";
inputNeutralTemperature = "3296.579476861167";
inputNeutralTint = "3.848452212530264";
inputNoiseReductionAmount = "<null>";
inputNoiseReductionContrastAmount = 0;
inputNoiseReductionDetailAmount = 0;
inputNoiseReductionSharpnessAmount = "0.5";
inputScaleFactor = 1;
}}
CR2 File:
{CIRAWFilterImpl {
inputBias = 3;
inputBoost = 1;
inputBoostShadowAmount = "0.9";
inputColorNoiseReductionAmount = "0.5";
inputDecoderVersion = 6;
inputDraftMode = 0;
inputEV = 0;
inputEnableNoiseTracking = 1;
inputEnableSharpening = 1;
inputEnableVendorLensCorrection = 0;
inputIgnoreOrientation = "<null>";
inputImageOrientation = 1;
inputLinearSpaceFilter = "<null>";
inputLuminanceNoiseReductionAmount = 0;
inputNeutralChromaticityX = "0.3575430840790828";
inputNeutralChromaticityY = "0.3599707869545071";
inputNeutralLocation = "[]";
inputNeutralTemperature = "4585.861752390336";
inputNeutralTint = "-11.18923977879745";
inputNoiseReductionAmount = "<null>";
inputNoiseReductionContrastAmount = 0;
inputNoiseReductionDetailAmount = 0;
inputNoiseReductionSharpnessAmount = "0.5";
inputScaleFactor = 1;
}}
Help?
This appears to be a regression in 10.10.2 and/or the latest RAW compatibility update, according to posts in Apple's Devforums. The only known workaround is to manually override inputDecoderVersion to 5.
Please also file a Radar, so that Apple takes notice.
is there a way to apply skphysics to a animated character? Okay I have my player play an animation when I move it around the screen and below is it's animation code but for some reason when I want to apply physics to my animation, I get an error saying wrong data type.
Sending 'SKSpriteNode *_strong' to parameter of incompatible type 'CGRect' (aka 'struct CGRect')
NO Reputation and I can't answer my own question so I posted here.
actually never mind I had to add this _Player.frame and I am hoping this is right and is putting physics on my character. However, please correct me if I am wrong. thanks.
- (void) Player {
_Player = [SKSpriteNode spriteNodeWithImageNamed:#"bird"];
_Player.xScale = 0.88;
_Player.yScale = 0.88;
_Player.position = CGPointMake(100, 100);
[self addChild:_Player];
// 1
NSMutableArray *PlayerCh = [NSMutableArray arrayWithCapacity:2];
// 2
for (int i = 1; i < 2; i++) {
NSString *mytextureName = [NSString stringWithFormat:#"bird%d", i];
SKTexture *ItsTexture = [SKTexture textureWithImageNamed:mytextureName];
[PlayerCh addObject:ItsTexture];
}
// 3
for (int i = 2; i > 1; i--) {
NSString *mytextureName = [NSString stringWithFormat:#"bird%d", i];
SKTexture *ItsTexture = [SKTexture textureWithImageNamed:mytextureName];
[PlayerCh addObject:ItsTexture];
}
// 4
_PlayerAnimation = [SKAction animateWithTextures:PlayerCh timePerFrame:0.1];
// SKPHYSICS FOR PLAYER
SKPhysicsBody *MYPLAYER = [SKPhysicsBody bodyWithCircleOfRadius:_Player]; // I get a error here.
}
Of course this program has to crash when it runs
[SKPhysicsBody bodyWithCircleOfRadius:_Player] expects a float not an SKPriteNode, what you probably want to do is change this line of code to the following:
SKPhysicsBody *MYPLAYER = [SKPhysicsBody bodyWithCircleOfRadius:_Player.size.width/2];
I'm trying to create a text field similar to Finder's file labels. I would like the last (second) line to be truncated in the middle.
I started with a multi-line NSTextField.
However, calling [self.cell setLineBreakMode:NSLineBreakByTruncatingMiddle]; results in a the text field showing only a single truncated line (no line breaks anymore).
Here is what it looks like in Finder:
If you want to wrap text like finder labels, using two labels doesn't do you any good since you need to know what the maximum breakable amount of text is on the first line. Plus, if you're building something that will display a lot of items two labels will overburden the GUI needlessly.
Set your NSTextField.cell like this:
[captionLabel.cell setLineBreakMode: NSLineBreakByCharWrapping];
Then find the code for "NS(Attributed)String+Geometrics" (Google it, it's out there). You must #import "NS(Attributed)String+Geometrics.h"
to measure text. It monkey patches NSString and NSAttributedString
I include the following code to wrap text exactly how Finder does in its captions. Using one label below the icon it assumes that, like Finder, there will be two lines of caption.
First this is how you will call the following code in your code:
NSString *caption = self.textInput.stringValue;
CGFloat w = self.captionLabel.bounds.size.width;
NSString *wrappedCaption = [self wrappedCaptionText:self.captionLabel.font caption:caption width:w];
self.captionLabel.stringValue = wrappedCaption ? [self middleTruncatedCaption:wrappedCaption withFont:self.captionLabel.font width:w] : caption;
Now for the main code:
#define SINGLE_LINE_HEIGHT 21
/*
This is the way finder captions work -
1) see if the string needs wrapping at all
2) if so find the maximum amount that will fit on the first line of the caption
3) See if there is a (word)break character somewhere between the maximum that would fit on the first line and the begining of the string
4) If there is a break character (working backwards) on the first line- insert a line break then return a string so that the truncation function can trunc the second line
*/
-(NSString *) wrappedCaptionText:(NSFont*) aFont caption:(NSString*)caption width:(CGFloat)captionWidth
{
NSString *wrappedCaption = nil;
//get the width for the text as if it was in a single line
CGFloat widthOfText = [caption widthForHeight:SINGLE_LINE_HEIGHT font:aFont];
//1) nothing to wrap
if ( widthOfText <= captionWidth )
return nil;
//2) find the maximum amount that fits on the first line
NSRange firstLineRange = [self getMaximumLengthOfFirstLineWithFont:aFont caption:caption width:captionWidth];
//3) find the first breakable character on the first line looking backwards
NSCharacterSet *notAlphaNums = [NSCharacterSet alphanumericCharacterSet].invertedSet;
NSCharacterSet *whites = [NSCharacterSet whitespaceAndNewlineCharacterSet];
NSRange range = [caption rangeOfCharacterFromSet:notAlphaNums options:NSBackwardsSearch range:firstLineRange];
NSUInteger splitPos;
if ( (range.length == 0) || (range.location < firstLineRange.length * 2 / 3) ) {
// no break found or break is too (less than two thirds) far to the start of the text
splitPos = firstLineRange.length;
} else {
splitPos = range.location+range.length;
}
//4) put a line break at the logical end of the first line
wrappedCaption = [NSString stringWithFormat:#"%#\n%#",
[[caption substringToIndex:splitPos] stringByTrimmingCharactersInSet:whites],
[[caption substringFromIndex:splitPos] stringByTrimmingCharactersInSet:whites]];
return wrappedCaption;
}
/*
Binary search is great..but when we split the caption in half, we dont have far to go usually
Depends on the average length of text you are trying to wrap filenames are not usually that long
compared to the captions that hold them...
*/
-(NSRange) getMaximumLengthOfFirstLineWithFont:(NSFont *)aFont caption:(NSString*)caption width:(CGFloat)captionWidth
{
BOOL fits = NO;
NSString *firstLine = nil;
NSRange range;
range.length = caption.length /2;
range.location = 0;
NSUInteger lastFailedLength = caption.length;
NSUInteger lastSuccessLength = 0;
int testCount = 0;
NSUInteger initialLength = range.length;
NSUInteger actualDistance = 0;
while (!fits) {
firstLine = [caption substringWithRange:range];
fits = [firstLine widthForHeight:SINGLE_LINE_HEIGHT font:aFont] < captionWidth;
testCount++;
if ( !fits ) {
lastFailedLength = range.length;
range.length-= (lastFailedLength - lastSuccessLength) == 1? 1 : (lastFailedLength - lastSuccessLength)/2;
continue;
} else {
if ( range.length == lastFailedLength -1 ) {
actualDistance = range.length - initialLength;
#ifdef DEBUG
NSLog(#"# of tests:%d actualDistance:%lu iteration better? %#", testCount, (unsigned long)actualDistance, testCount > actualDistance ? #"YES" :#"NO");
#endif
break;
} else {
lastSuccessLength = range.length;
range.length += (lastFailedLength-range.length) / 2;
fits = NO;
continue;
}
}
}
return range;
}
-(NSString *)middleTruncatedCaption:(NSString*)aCaption withFont:(NSFont*)aFont width:(CGFloat)captionWidth
{
NSArray *components = [aCaption componentsSeparatedByString:#"\n"];
NSString *secondLine = [components objectAtIndex:1];
NSString *newCaption = aCaption;
CGFloat widthOfText = [secondLine widthForHeight:SINGLE_LINE_HEIGHT font:aFont];
if ( widthOfText > captionWidth ) {
//ignore the fact that the length might be an odd/even number "..." will always truncate at least one character
int middleChar = ((int)secondLine.length-1) / 2;
NSString *newSecondLine = nil;
NSString *leftSide = secondLine;
NSString *rightSide = secondLine;
for (int i=1; i <= middleChar; i++) {
leftSide = [secondLine substringToIndex:middleChar-i];
rightSide = [secondLine substringFromIndex:middleChar+i];
newSecondLine = [NSString stringWithFormat:#"%#…%#", leftSide, rightSide];
widthOfText = [newSecondLine widthForHeight:SINGLE_LINE_HEIGHT font:aFont];
if ( widthOfText <= captionWidth ) {
newCaption = [NSString stringWithFormat:#"%#\n%#", [components objectAtIndex:0], newSecondLine];
break;
}
}
}
return newCaption;
}
Cheers!
PS Tested in prototype works great probably has bugs...find them
I suspect there are two labels there. The top one contains the first 20 characters of a file name, and the second contains any overflow, truncated.
The length of the first label is probably restricted based on the user's font settings.
I am working on a Cocoa Mac OSX app, and I am wondering if it is possible to present the contents of an NSRange found by:
NSRange range;
range.location = 4;
range.length = 4;
as an NSString?
e.g. in the example above, if I had a string with contents "abcdefgh", presenting the contents of the above range as a string would give "efgh". Is this possible?
Code:
NSString *string = #"abcdefgh";
NSRange range;
range.location = 4;
range.length = 4;
NSString *subString = [string substringWithRange:range];
NSLog(#"%#",subString);
Output:
efgh
Try the method substringWithRange from NSString.
NSString* original = #"abcdefgh";
NSLog(#"Substring: %#", [original substringWithRange:range]);
When I call -description on an NSData object, I see a pretty Hex string of the NSData object's bytes like:
<f6e7cd28 0fc5b5d4 88f8394b af216506 bc1bba86 4d5b483d>
I'd like to get this representation of the data (minus the lt/gt quotes) into an in-memory NSString so I can work with it.. I'd prefer not to call -[NSData description] and then just trim the lt/gt quotes (because I assume that is not a guaranteed aspect of NSData's public interface and is subject change in the future).
What's the simplest way to get this representation of an NSData object into an NSString object (other than calling -description)?
Keep in mind that any String(format: ...) solution will be terribly slow (for large data)
NSData *data = ...;
NSUInteger capacity = data.length * 2;
NSMutableString *sbuf = [NSMutableString stringWithCapacity:capacity];
const unsigned char *buf = data.bytes;
NSInteger i;
for (i=0; i<data.length; ++i) {
[sbuf appendFormat:#"%02X", (NSUInteger)buf[i]];
}
If you need something more performant try this:
static inline char itoh(int i) {
if (i > 9) return 'A' + (i - 10);
return '0' + i;
}
NSString * NSDataToHex(NSData *data) {
NSUInteger i, len;
unsigned char *buf, *bytes;
len = data.length;
bytes = (unsigned char*)data.bytes;
buf = malloc(len*2);
for (i=0; i<len; i++) {
buf[i*2] = itoh((bytes[i] >> 4) & 0xF);
buf[i*2+1] = itoh(bytes[i] & 0xF);
}
return [[NSString alloc] initWithBytesNoCopy:buf
length:len*2
encoding:NSASCIIStringEncoding
freeWhenDone:YES];
}
Swift version
private extension Data {
var hexadecimalString: String {
let charA: UInt8 = 0x61
let char0: UInt8 = 0x30
func byteToChar(_ b: UInt8) -> Character {
Character(UnicodeScalar(b > 9 ? charA + b - 10 : char0 + b))
}
let hexChars = flatMap {[
byteToChar(($0 >> 4) & 0xF),
byteToChar($0 & 0xF)
]}
return String(hexChars)
}
}
I agree on the solution not to call description which is to be reserved for debugging, so good point and good question :)
The easiest solution is to loop thru the bytes of the NSData and construct the NSString from it. Use [yourData bytes] to access the bytes, and build the string into an NSMutableString.
Here is an example by implementing this using a category of NSData
#interface NSData(Hex)
-(NSString*)hexRepresentationWithSpaces_AS:(BOOL)spaces;
#end
#implementation NSData(Hex)
-(NSString*)hexRepresentationWithSpaces_AS:(BOOL)spaces
{
const unsigned char* bytes = (const unsigned char*)[self bytes];
NSUInteger nbBytes = [self length];
//If spaces is true, insert a space every this many input bytes (twice this many output characters).
static const NSUInteger spaceEveryThisManyBytes = 4UL;
//If spaces is true, insert a line-break instead of a space every this many spaces.
static const NSUInteger lineBreakEveryThisManySpaces = 4UL;
const NSUInteger lineBreakEveryThisManyBytes = spaceEveryThisManyBytes * lineBreakEveryThisManySpaces;
NSUInteger strLen = 2*nbBytes + (spaces ? nbBytes/spaceEveryThisManyBytes : 0);
NSMutableString* hex = [[NSMutableString alloc] initWithCapacity:strLen];
for(NSUInteger i=0; i<nbBytes; ) {
[hex appendFormat:#"%02X", bytes[i]];
//We need to increment here so that the every-n-bytes computations are right.
++i;
if (spaces) {
if (i % lineBreakEveryThisManyBytes == 0) [hex appendString:#"\n"];
else if (i % spaceEveryThisManyBytes == 0) [hex appendString:#" "];
}
}
return [hex autorelease];
}
#end
Usage:
NSData* data = ...
NSString* hex = [data hexRepresentationWithSpaces_AS:YES];
Just wanted to add that #PassKits's method can be written very elegantly using Swift 3 since Data now is a collection.
extension Data {
var hex: String {
var hexString = ""
for byte in self {
hexString += String(format: "%02X", byte)
}
return hexString
}
}
Or ...
extension Data {
var hex: String {
return self.map { b in String(format: "%02X", b) }.joined()
}
}
Or even ...
extension Data {
var hex: String {
return self.reduce("") { string, byte in
string + String(format: "%02X", byte)
}
}
}
I liked #Erik_Aigner's answer the best. I just refactored it a bit:
NSData *data = [NSMutableData dataWithBytes:"acani" length:5];
NSUInteger dataLength = [data length];
NSMutableString *string = [NSMutableString stringWithCapacity:dataLength*2];
const unsigned char *dataBytes = [data bytes];
for (NSInteger idx = 0; idx < dataLength; ++idx) {
[string appendFormat:#"%02x", dataBytes[idx]];
}
In Swift you can create an extension.
extension NSData {
func toHexString() -> String {
var hexString: String = ""
let dataBytes = UnsafePointer<CUnsignedChar>(self.bytes)
for (var i: Int=0; i<self.length; ++i) {
hexString += String(format: "%02X", dataBytes[i])
}
return hexString
}
}
Then you can simply use:
let keyData: NSData = NSData(bytes: [0x00, 0xFF], length: 2)
let hexString = keyData.toHexString()
println("\(hexString)") // Outputs 00FF
Sadly there's no built-in way to produce hex from an NSData, but it's pretty easy to do yourself. The simple way is to just pass successive bytes into sprintf("%02x") and accumulate those into an NSMutableString. A faster way would be to build a lookup table that maps 4 bits into a hex character, and then pass successive nybbles into that table.
While it may not be the most efficient way to do it, if you're doing this for debugging, SSCrypto has a category on NSData which contains two methods to do this (one for creating an NSString of the raw byte values, and one which shows a prettier representation of it).
http://www.septicus.com/SSCrypto/trunk/SSCrypto.m
Seeing there is a Swift 1.2 snippet in the comments, here's the Swift 2 version since C style for loops are deprecated now.
Gist with MIT license and two simple unit tests if you care.
Here's the code for your convenience:
import Foundation
extension NSData {
var hexString: String {
let pointer = UnsafePointer<UInt8>(bytes)
let array = getByteArray(pointer)
return array.reduce("") { (result, byte) -> String in
result.stringByAppendingString(String(format: "%02x", byte))
}
}
private func getByteArray(pointer: UnsafePointer<UInt8>) -> [UInt8] {
let buffer = UnsafeBufferPointer<UInt8>(start: pointer, count: length)
return [UInt8](buffer)
}
}
Assuming you have already set:
NSData *myData = ...;
Simple solution:
NSString *strData = [[NSString alloc]initWithData:myData encoding:NSUTF8StringEncoding];
NSLog(#"%#",strData);