小编Sea*_*ean的帖子

使用Objective-C块

今天我正在试验Objective-C的块,所以我觉得我很聪明,并在NSArray中添加了一些我在其他语言中看到的功能风格的收集方法:

@interface NSArray (FunWithBlocks)
- (NSArray *)collect:(id (^)(id obj))block;
- (NSArray *)select:(BOOL (^)(id obj))block;
- (NSArray *)flattenedArray;
@end
Run Code Online (Sandbox Code Playgroud)

collect:方法接受一个为数组中的每个项调用的块,并期望使用该项返回某些操作的结果.结果是收集所有这些结果.(如果块返回nil,则不会向结果集添加任何内容.)

select:方法将返回一个只包含原始项的新数组,当作为参数传递给块时,块返回YES.

最后,flattenedArray方法迭代数组的项目.如果一个项是一个数组,它会递归调用flattenedArray并将结果添加到结果集中.如果该项不是数组,则将该项添加到结果集中.一切都完成后返回结果集.

所以现在我有了一些基础设施,我需要一个测试用例.我决定在系统的应用程序目录中找到所有包文件.这就是我想出的:

NSArray *packagePaths = [[[NSSearchPathForDirectoriesInDomains(NSAllApplicationsDirectory, NSAllDomainsMask, YES) collect:^(id path) { return (id)[[[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil] collect:^(id file) { return (id)[path stringByAppendingPathComponent:file]; }]; }] flattenedArray] select:^(id fullPath) { return [[NSWorkspace sharedWorkspace] isFilePackageAtPath:fullPath]; }];
Run Code Online (Sandbox Code Playgroud)

是的 - 这一切都是一线而且很可怕.我尝试了一些方法来添加换行符和缩进以尝试清理它,但它仍然感觉实际算法在所有噪声中都丢失了.不过,我不知道这只是一种语法问题,还是我使用功能风格的亲戚体验.

为了比较,我决定采用"老式的方式"并使用循环:

NSMutableArray *packagePaths = [NSMutableArray new];
for (NSString *searchPath in NSSearchPathForDirectoriesInDomains(NSAllApplicationsDirectory, NSAllDomainsMask, YES)) {
    for (NSString *file in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:searchPath error:nil]) {
        NSString …
Run Code Online (Sandbox Code Playgroud)

coding-style objective-c

17
推荐指数
1
解决办法
2万
查看次数

重新定义Smalltalk类的实例变量

我从来没有使用过Smalltalk,但我已经阅读了很多关于它的内容,它一直引起我的兴趣.我已经看到了程序运行的很酷的演示,只需更改程序对象使用的类的方法就可以改变正在运行的程序的行为.它显然是强大的东西,我理解它是如何工作的.我似乎无法确定的是,当您想要添加,删除或重命名该类的实例变量时,现有的类实例会发生什么.

我无法想象如何改变所有类在正在运行的程序中使用的实例变量,并且仍然期望该类的现有实例在之后正确运行.也许我正在添加一个我需要初始化的新实例变量,以及先前已存在的方法已被更改为依赖于此变量的位置.难道我最终没有任何运行代码的可怕故障,该代码具有该类的实时实例?或者,如果实例变量的含义发生了变化,我现在期望在那里存储一种不同类型的对象,而不是以前呢?有某种"升级"机制吗?或者通常的做法是让前面的实例崩溃并烧毁?或者这只是"我们不会在运行程序时做那种事情并希望它们能够存活下来的情况".

我能想到的唯一合理干净的方法是,当您更改实例变量定义时,它实际上可能会创建一个全新的类,并且在更改之前,旧实例继续使用旧的类定义(现在是由于名称被重新定义为新的类定义,因此无法按名称访问.也许这是最合乎逻辑的解释 - 但由于我没有找到任何直接解释这个过程的东西,我想我会问这里,看看有什么样的有趣信息让我感到兴奋.:)

smalltalk

8
推荐指数
1
解决办法
1094
查看次数

对数组中的字符串不区分大小写的NSPredicate?

我有一种情况,我想通过用户名密钥从我的核心数据存储中获取对象,但我希望比较不区分大小写.我的谓词是这样的:

username IN $usernames
Run Code Online (Sandbox Code Playgroud)

然后我用一个字符串数组进行变量替换,这些字符串是我想要查找的用户名.它有效,但区分大小写.我想这样做,我想:

username IN[c] $usernames
Run Code Online (Sandbox Code Playgroud)

不幸的是,这似乎不起作用.字符串比较仍必须以区分大小写的方式进行.(我不会收到有关它是不受支持的查询的错误.)

有没有不同的方法来编写这个谓词,所以它以我需要的方式工作,或者我只是遗漏了一些明显的东西?

cocoa core-data nspredicate

8
推荐指数
1
解决办法
5198
查看次数

glVertexPointer()什么时候复制数据?

在调用时glVertexPointer()(以及其他相关函数)使用堆栈上的顶点数组是否安全?当OpenGL实际上从传入的结构中复制数据时,我不清楚.

如果不安全,那么你怎么知道什么时候可以安全地销毁/重用你传递给的结构glVertexPointer()

(不使用VBO)

opengl

8
推荐指数
1
解决办法
3651
查看次数

你对Objective-C中的返回类型有多小心?

假设您有一个方法返回一个新生成的NSArray实例,该实例是使用NSMutableArray内部构建的.你总是做这样的事情:

- (NSArray *)someArray {
    NSMutableArray *mutableArray = [[NSMutableArray new] autorelease];
    // do stuff...
    return [NSArray arrayWithArray:mutableArray];  // .. or [[mutableArray copy] autorelease]
}
Run Code Online (Sandbox Code Playgroud)

或者你只是将可变数组对象保持原样并直接返回它,因为NSMutableArray是NSArray的子​​类:

- (NSArray *)someArray {
    NSMutableArray *mutableArray = [[NSMutableArray new] autorelease];
    // do stuff...
    return mutableArray;
}
Run Code Online (Sandbox Code Playgroud)

就个人而言,当我从这样的方法返回时,我经常将一个可变数组转换为NSArray只是因为我觉得它更"安全"或更"正确".虽然说实话,我从来没有遇到过将一个可变数组转换为NSArray的问题,所以它实际上可能不是问题 - 但这样的情况是否有最佳实践?

cocoa coding-style objective-c

7
推荐指数
2
解决办法
1512
查看次数

NSTextView在图层上没有显示红色拼写错误的下划线

NSTextViewa NSView是图层支持(-wantsLayer == YES)的子视图时,它不会为拼写错误的单词呈现波浪形的红色下划线.重现这一点就是制作一个空的Cocoa项目,打开笔尖,拖入NSTextView窗口,并切换窗口的内容视图以获得一个图层.繁荣 - 没有更多的红色下划线.

我做了一些搜索,这似乎是一个已知的情况,自10.5以来一直如此.但是,我找不到的是它的解决方法.NSTextView在图层支持的视图中,是否无法获取下划线?

我能想象压倒一切NSTextViewdrawRect:,并使用布局管理器找到合适的临时属性组表示拼写错误的正确rects然后绘制红色波浪线喽,但这当然是一个总的黑客.我也可以想象苹果公司在10.7(或许)中修复此问题,突然我的应用程序会有双重下划线或其他东西.


[更新]我的解决方法

我当前的解决方法受到nptacek提到的拼写检查委托方法的启发,这促使我深入挖掘我之前没有注意到的路径,所以我将接受这个答案但是发布我为后代所做的和/或进一步的讨论.

我正在运行10.6.5.我有一个NSTextView的子类,它是NSClipView的自定义子类的文档视图,后者又是我的窗口contentView的子视图,它打开了图层.在玩这个时,我最终将所有自定义注释掉,但拼写检查仍然无法正常工作.

我相信,我发现了两个截然不同的问题:

#1是NSTextView,当托管在图层支持的视图中时,甚至不打算绘制拼写错误的下划线.(我根据谷歌的搜索结果表明,它在10.5天内可能已经有一段时间绘制了下划线,但没有在正确的位置 - 所以Apple可能只是完全禁用它们以避免10.6中的问题.我不确定我的定位方式也可能有一些副作用,导致它们在我的情况下根本不出现.目前未知.)

#2就是当NSTextView处于这种与图层相关的情况时,即使将-isContinuousSpellCheckingEnabled设置为YES,它在您输入时似乎也没有正确地将文本标记为拼写错误.我通过实现一些拼写检查委托方法来验证这一点并观察NSTextView发送有关更改的消息但从未通知将任何文本范围设置为拼写错误 - 即使显示拼写错误的单词会在TextEdit中显示红色下划线(和其他文本视图在其他应用程序中).我还覆盖了NSTextView的-handleTextCheckingResults:forRange:types:options:orthography:wordCount:看看它看到了什么,它看到了同样的东西.好像NSTextView正在主动设置光标下的单词没有拼写错误,然后当用户键入一个空格或远离它或其他什么时,它没有' 重新检查拼写错误.不过,我不完全确定.

好的,所以要解决#1,我覆盖-drawRect:在我的自定义NSTextView子类中看起来像这样:

- (void)drawRect:(NSRect)rect
{
    [super drawRect:rect];
    [self drawFakeSpellingUnderlinesInRect:rect];
}
Run Code Online (Sandbox Code Playgroud)

然后我实现了-drawFakeSpellingUnderlinesInRect:使用layoutManager获取包含NSSpellingStateAttributeName作为临时属性的文本范围,并渲染一个合理接近标准OSX拼写错误点图案的点图案.

- (void)drawFakeSpellingUnderlinesInRect:(NSRect)rect
{
    CGFloat lineDash[2] = {0.75, 3.25};

    NSBezierPath *underlinePath = [NSBezierPath bezierPath];
    [underlinePath setLineDash:lineDash count:2 phase:0];
    [underlinePath setLineWidth:2];
    [underlinePath setLineCapStyle:NSRoundLineCapStyle];

    NSLayoutManager *layout = [self layoutManager];
    NSRange checkRange = NSMakeRange(0,[[self string] length]);

    while (checkRange.length …
Run Code Online (Sandbox Code Playgroud)

cocoa objective-c nstextview appkit

6
推荐指数
1
解决办法
2347
查看次数

使用Cocoa垃圾收集泄漏内存

我一直在撞墙,试图弄清楚我在垃圾收集的Cocoa应用程序中是如何发生内存泄漏的.(活动监视器中的内存使用量会增长和增长,使用GC监视器工具运行应用程序也会显示不断增长的图形.)

我最终将它缩小到我的代码中的单个模式.数据被加载到NSData中,然后由C库解析(数据的字节和长度被传递到它中).C库具有回调函数,它将触发并返回子字符串的起始指针和长度(以避免内部复制).但是,出于我的目的,我需要将它们转换为NSStrings并保持一段时间.我是通过使用NSString的initWithBytes:length:encoding:方法完成的.我假设会复制字节,NSString会适当地管理它,但是出了问题,因为这会像疯了一样泄漏.

此代码将"泄漏"或以某种方式欺骗垃圾收集器:

- (void)meh
{
    NSData *data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"holmes" ofType:@"txt"]];
    const int substrLength = 80;

    for (const char *substr = [data bytes]; substr-(const char *)[data bytes] < [data length]; substr += substrLength) {
        NSString *cocoaString = [[NSString alloc] initWithBytes:substr length:substrLength encoding:NSUTF8StringEncoding];
        [cocoaString length];
    }
}
Run Code Online (Sandbox Code Playgroud)

我可以将它放在计时器中,只需观察活动监视器以及GC监视器仪器的内存使用情况.(holmes.txt是594KB)

这不是世界上最好的代码,但它显示了问题.(我正在运行10.6,该项目的目标是10.5 - 如果这很重要).我阅读了垃圾收集文档并注意到了一些可能的陷阱,但我认为我没有做任何明显违反规则的事情.不过要问,不要伤心.谢谢!

项目拉链

这是对象图的图片,只是增长和增长:

替代文字

cocoa garbage-collection

5
推荐指数
1
解决办法
1301
查看次数

NSScrollView内的NSTextView不会滚动:(

我在一个独立的Cocoa测试应用程序中有以下代码:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    NSView *contentView = [window contentView];

    NSTextStorage *textStorage = [NSTextStorage new];
    NSLayoutManager *layoutManager = [NSLayoutManager new];
    NSTextContainer *textContainer = [NSTextContainer new];

    [textContainer setHeightTracksTextView:YES];
    [textContainer setWidthTracksTextView:YES];
    [textStorage addLayoutManager:layoutManager];
    [layoutManager addTextContainer:textContainer];

    NSScrollView *scrollView = [[NSScrollView alloc] initWithFrame:[contentView bounds]];
    [scrollView setHasVerticalScroller:YES];
    [scrollView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
    [scrollView setBorderType:NSNoBorder];

    NSRect textFrame;
    textFrame.origin = NSZeroPoint;
    textFrame.size = [NSScrollView contentSizeForFrameSize:[scrollView frame].size hasHorizontalScroller:NO hasVerticalScroller:YES borderType:NSNoBorder];

    NSTextView *textView = [[[NSTextView alloc] initWithFrame:textFrame textContainer:textContainer] autorelease];
    [textView setAutoresizingMask:NSViewWidthSizable];

    [scrollView setDocumentView:textView];

    [contentView addSubview:scrollView];
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试在NSTextView + NSScrollView组合中设置所涉及对象的整个层次结构(包括文本系统对象),以便了解它们如何一起工作.但是,当我运行它并开始向文本视图添加一堆行时,当文本变得比视图高时,它不会滚动.就像NSScrollView和NSTextView彼此不了解一样.我错过了什么联系,让一切都在这里正确沟通?

编辑:是的,这是漏洞和丑陋的.:)这只是为了试图确定这里发生了什么,而不是生产代码或我将直接再次使用的任何东西.诺言.

cocoa objective-c appkit

5
推荐指数
1
解决办法
3245
查看次数

为什么界面生成器会让我感觉不舒服?

我对Cocoa for MacOSX很新,但我不禁觉得我一直在与Interface Builder对抗.

我目前的情况是我正在构建一个具有多个自定义控件和视图的应用程序.我开始在Interface Builder中构建应用程序,因为它最初很容易拖动并使用正确的颜色和正确的自动调整规则将它们放入正确的位置.然而,现在是开始构建我的自定义控件和视图的时候了 - 我无法在Interface Builder中很好地代表它,而无需完成构建IBPlugin的工作!我所知道的唯一另一个选择是拥有一个Interface Builder文档,其中包含一堆"自定义视图",只更改了类.即使对IB感到麻烦,这似乎也毫无意义 - 尤其是考虑到这些控件和视图将具有需要设置的颜色等属性的事实 - 就像IB文档中已有的其他视图和控件一样.所以现在我已经在两个断开连接的位置设置了可视化属性,似乎与IB的一个潜在优势相反,这使得相对容易调整应用程序的UI而无需深入研究代码.

我还面临一种情况,即一些控件根据数据或当前选择更改属性(如颜色).所以现在我在Interface Builder中指定了控件的初始默认颜色,但是我必须在代码中指定数据驱动的颜色?Interface Builder似乎再次让我必须在它的世界和代码之间拆分一些表示设置.我想有可能通过一个了解我的数据或状态或其他的复杂插件来解决这个问题,但似乎我最终维护了大量的支持代码,因此Interface Builder的经验仍然是"正确的".

我经常看到的其他一些内容是IB允许您轻松定义组件之间的绑定."你可以不用编写任何代码就可以做到!" 同样,我可能会遗漏一些东西,但据我所知,将一个属性绑定到另一个属性是一行代码.在IB中的框中设置几个属性真的比编写一行代码要好吗?为什么在表示层的规范中添加相当于应用程序逻辑的更好?

就像我在公开场合所说的那样,我对这个Cocoa的东西很新,但是我觉得我要么缺少一些关于如何使用Interface Builder的非常重要的东西,要么它主要是设计用于具有高"哇"的琐碎演示应用程序因子.

macos cocoa objective-c interface-builder

4
推荐指数
2
解决办法
777
查看次数